React Course Notes : Nested Components (Part 2)

20180923

In part one of nesting components, lets take a look at this image right here. Every border represents a component. The goal is to make one component that nests are two components.

  • The red one
    The red one is “Greeter”
    The red component is going to be what’s known as a container component. A container components do maintain state. Container components maintain state and render children.

In this case my red component is going to maintain the name state when it gets changed by the blue component. It will render the green component and that’s because it automatically rebounders its children when its state changes, and the children rely on it.

  • The green one
    The green one is “GreeterMessage”
    This type of component is a presentational component. A presentational component like this green one renders something visible to the screen like “Hello Andrew!” or “This is the default message!!!”

The key is that presentational components don’t maintain state. They kind of dummy components that simply render stuff to the browser and they call functions when a user interacts.

  • The blue one
    The blue one is “GreeterForm “
    The blue component it responds to user input. So in this case I have an input field and a button gets clicked.

I want to do this to maintain the single responsibility principle inside of react.

Components can get unnecessarily large and complex. This makes them harder to work with impossible to reuse and prone to errors by breaking things out into smaller testable components.

I can create better apps that have more functionality but without more complex code. So what I’ve done here is actually created two different types of components.

I am going to be using these terms to describe my react components but they don’t actually require us to do anything special.

Now I already have static components set up, but it’s time to make them dynamic and get rid of the current ones.

Right now when I click the submit button or hit enter, it’s going to automatically submit the form but it doesn’t do anything in my app.

  • So to fix this I am going to be using the onSubmit attribute which I’ve explored before and I want to set it equal to a function.

<form onSubmit={this.onFormSubmit}>

So I am going to open and close curly braces to put a JSX right inside of here. And the function I am going to call is this.onFormSubmit.

  • Now onFormSubmit is not defined, so up above the render function, I’m going to define onFormSubmit.

onFormSubmit: function(e){

e.preventDefault();

},

I set it equal to an anonymous function and that anonymous function is going to get the “e” argument. Remember that’s just short for an event. And it’s not special to react, it’s built in javascript.

And what I am going to do is call “e.preventDefault”. This is going to prevent the browser from refreshing which is the default behavior of a form submission.

  • The next thing to do is to get the name var name = this.refs.name.value;

And remember right here (21 line) I set ref =”name” and that means I can access the name property on refs and I am going to poll the value out.

var name = this.refs.name.value;

  • Now at this point I have my name and I am going to have an if statement that validates the length

If name.length is greater than zero. So this if statement is only ever going to run if my component received a valid input.

if(name.length > 0){

}

If it did receive valid input I want to do two things:

  • First I want to empty the field out of this.refs.name.value equals then I am going to put empty quotes to clear the field.

if(name.length > 0){

this.refs.name.value ='';

}

  • The next thing I want to do is pass the name up to the Greeter component. That might be a little confusing so let’s go ahead and head back into the image.

When the set name button gets clicked, the blue component is going to get the value from the form. It’s also going to call stuff like “e.preventDefault” that has to do with the UI and then it’s going to pass that name up to the red function which is going to set its state based on the argument.

And the reason I am doing this is to maintain this container component and keep the blue component as loosely coupled as possible. Meaning it doesn’t need to know what gets done with the name. All it needs to do is call a function and pass the name to it.

So to do that, I am actually going to pass a function from Greeter component as a prop into the GreeterForm component.

Pass a function to GreeterForm

Now I want to find that function in Greeter and I am going to do that just kind of like we do right here:

  • Inside of this function I call “this.setState”. I do still want to do that only in this case instead of having the “e” argument. I am going to get the “name”.

onButtonClick:function(name){

}

  • Instead of calling it onButtonClick, I’m going to call it “handleNewName”. And inside of the function the only thing I need to do is call this.setState so I can delete everything else.

handleNewName:function(name){

this.setState({

)};

}

  • I am going to pass an object of the attributes I want to set. In this case I am just going to set a “name” equal to the “name” argument.

handleNewName:function(name){

this.setState({

name:name

)};

}

  • The next step is to actually pass it down to GreeterForm and delete the old form I had.
  • Inside of GreeterForm I am going to pass a promp down just like I do below with the Greeter component. I’m going to name the prop on a new name and set it equal to this.handleNewName.

<GreeterForm onNewName={this.handleNewName}/>

When having a parent component that’s handling an event from a child, usually call the parent handle followed by the name I chose. And then I call in the child with “on” followed by the name I chose.

So right now the GreeterForm has this new prop. I can access it via .NewName.

And all that does is it calls this function that sets the state.

So let’s go ahead and do that inside of GreeterForm component.

  • All I’m going to do right after I clear the value out is call this.props.onNewName passing in the “name” value which I’ve already validated.

this.props.onNewName(name);

  • I can head over to the browser where I have my app running on port 3000 and refresh the page.

You can see I have my static some H1 and that’s not going to do anything yet. But Ido still have my wired up “Hello Andrew!” component.

  • I’m going to type Mike in here
  • Hit the button and you can see that “Hello Mike!” prints to the screen

My child component is able to stay simple but still update the state of the parent container component. And this is how I am going to make data flow inside of our react JS applications.

So back over inside of Atom, I can do the exact same thing with GreeterMessage component.

It’s going to be a lot simpler GreeterMessage and it doesn’t respond to user events at all. So we have to do is access the props in the render function using JSX to print them to the screen and then I am done.

  • Down below inside of Greeter, I have GreeterMessage right here. All I need to do is pass in the name and the message name is equal to name. I’m going to go ahead and delete the H1 and the <p> tag in the

  • Up above inside of Greeter message, I’m going to access var name equals this.props.name

And then inside of some H1, I’m going to print Hello open and close in curly braces. I want to show the “name” variable here and I put an exclamation mark at the end.

var name = this.props.name;

return(

 

Hello {name}!

 

  • I save this file and refresh the browser

This time I see “Hello Andrew” print first.

  • And if I type something in the input field like “Vikram” and click set name

You can see “Hello Vikram” print to the screen.

Pass a message up inside of GreeterMessage

  • To kick this off, I’m going to start in the Greeter component passing in the message prop.

I’m going to call the prop “message” and set it equal to the “message” variable.

<GreeterMessage name={name} message={message}/>

  • Then up above inside of GreeterMessage I can pull this prop out into the message variable this.props.message

var message = this.props.message;

  • Inside of my paragraph tag instead of having static text, I’m going to use a little JSX.

<p>{message}</p>

Referenced the message variable and save the file and I am done.

  • Now if I refresh the browser you can see I have our default message here along with my default name

And the form still works so I can type in anything.

  • Hit enter and it shows right here in Greeter Message component

So let’s cover what’s happening really quick one more time

  • I have red container component that maintains the state every time its state changes.
  • Red container component updates its children if necessary.
  • Now in this case it’s only going to update the green component because the blue component doesn’t care about the state of its parent.

When the blue component has the set name button clicked or the form submitted via the enter key it does a few things:

  • First up it validates the data and then it calls a function that’s passed in from the parent.
  • This parent function. All it does is it sets the state right here of Greeter.
  • Because react automatically renders components that rely on a changed state are GreeterMessage, component gets rendered and the new name is shown.