Learn React.js in this interactive tutorial
Hello, Welcome to the Learning React lab. Let's write a simple React component. We'll use the class syntax, class Hello extends the React.Component class. Inside the class we define a render() function. The render function returns the HTML that we want the component to display in the browser. Then we use the ReactDOM variable to render this component into the mountNode variable. The variables React, ReactDOM and mountNode are all globally defined for you. Note how we treat the component here as if it was just another HTML element. When we execute this code, "Hello React" shows up on the screen. This is a live editor here on the left which means you can start playing with this code even while I am talking. Try it. To render any changes you do in the live editor click the execute button or press CTRL+Enter. Your first simple challenge is to render the word Easy on the screen using the simple component we defined. Note the challenge box that just appeared with the details of the challenge. When you solve the challenge correctly you can click the continue button.
You can pause/play a session at any time using the controls you see here at the bottom, you can also control the speed of the audio and show/hide the subtitles with these links. A lab has many sessions and sub-sessions which you can see as links here. You can jump back and forth between sessions as needed. The next session will not start automatically as this is mostly an interactive environment. At the end of each session, you'll get a challenge to validate what you learned in the session, but you can always use the navigator links to jump to any session at any time. Try to do all the challenges though because the better way to learn is to build something with what you're learning. Your challenge for this session is to rewrite the simple Hello component from scratch. So I am going to reset the editor now and I want you to write the Hello component from memory. Try not to cheat and seek backward to see the code, it's really easy, a class that has a render() function that returns HTML. Ready? Go.
If you wan't to be notified when we publish future interactive labs like this one, you can signup with your email address here. To continue with the lab, click the Continue button in the navigator. The actual code for this signup form is what you see in the editor, it's a simple React component that returns an HTML form, and notice that you can use bootstrap classes here. On form submit, this component issues an Ajax request and actually subscribes the user-typed email address on the backend, and you can see the code to handle the response and errors if any.
The example Hello component we've been using so far is simple. To define a component, we make a class that extends the React.Component class, and define a render function in that class. The render function returns the virtual DOM node that we want React to take to the browser. The component name can be anything. In fact, go ahead and rename this Hello component into Button (instead of Hello), and change the content of the component to return an HTML button element element instead of the div. Use the label "submit" for the button. See the desired output in the challenge box
We make the component return a button instead of the div and use the label "submit" for the button, and we'll rename Hello into Button. Note how we always use a title case for the component's name because otherwise we might get a conflict with actual HTML elements like our button element, for example
Now that we defined an initial state and saw how to read it, inside the render method, let's change it on click. We'll need to define a click event on the button element. We do so by supplying an onclick property to it. The value of this onclick property has to be a function reference clicks the button. Let's name this function handleClick. We'll define as an instance property on this class so we can get a reference for it using this.handleClick handleclick's job is simple. read the current label's value, increment it, and update the component state with the incremented value. We read the current label using this.state.label, add 1 to that, and this incremented value is what we want to write back to the the state. To update a component state, we use the setState instance method. It takes an object and uses that object to update the state the button's label property will now be the previous label property incremented. Go ahead and test this code, the button should now increment its value on click. Your challenge now is to make the button double its value on click instead of incrementing it.
To double the value, instead of adding 1 to the current value, we just multiply it by 2. Now the label value will double on each click.
We don't need the button to show the incremented value any more so let's make its label a simple +1 to label its operation. The idea here, when we click the button, we want the Result div to change it's value to reflect the newly incremented value. But we do have a problem here. The label's value that we previously incremented is owned by the button component and we now need this Result component to have access to that value. The Result component is currently a sibling of the Button component in our DOM tree. To make the incremented value available for both sibling components, we need to move it one level up to the parent Root component We move both the state object and the event that's handling the update call on the state. However, with this move, the names we used before don't apply here. It's not the button's label any more. Let me rename that into counter instead. To get this counter to appear in the Result component we pass it to the component as a property, I'll do counter equals this.state.counter. Now the Result component receives a property called counter and we can use the first argument to the component, which I'll name props, to read that value. We read the counter value using props.counter. The initial value 0 shows up in the Result component div now. I am going to also rename handleClick here to incrementCounter to make the next change easier to understand. The handleClick event on the button component is not going to work any more because we moved it. But we can have the Root component tell the Button component what function to execute on Click by also passing a prop to it but this time, the prop value we pass is a function reference instead of a primitive value. onClick is this.incerementCounter. Inside the button component, we'll have the onClick event fire this received prop which we can access here using this.props.onClick. Note the small difference in accessing the props object between the class syntax and the function syntax for components. The Button component is no longer a stateful component so we can actually convert it into a function component here but in the next session, we'll do one other feature that's better suited for the class syntax so I'm gonna keep it on that syntax for now. Quick review. We moved the state's counter value to the Root component, passed it down to the Result component using a prop, and passed an onClick handler function reference to the button component. Now the button component can basically tell the Root component to increment the counter value on each click Your challenge now is to render 2 buttons instead of one. Don't define any other components. Just re-use what we have. Both buttons should increment the displayed counter value in the Result component
We simply re-use the button component inside the Root component like this We can re-use a component as many times as we want. In the next session. We'll see how to customize a component using its props object
This problem can be solved in many ways. We first need to make the incrementCounter method receive the incrementValue as an argument and we'll use this incrementValue instead of the one here Now to make each button send it's correct increment value we can simply define a local function on the component instance, call that function handleClick, and in that function call the parent onClick function using the increment property of the button component instance and now we wire the onClick event here with this.handleClick This way the button component will send its own increment prop value to the incrementCounter method on the Root component. Go ahead and test our code so for the buttons should increment by 1, 5, and 10
Let's now do something a little bit more challenging but let's review first. We defined 3 components, both the Button component and the Root component used the class syntax. We use the class syntax when we need to use the state object or when we need to define custom event handlers and a few more cases we'll cover in future sessions You should use the function syntax that we used for the Result component whenever the component is purely presentational. We made the Button component re-usable by passing down an increment property. This allowed us to create many buttons with different increments Since we moved the counter value to be part of the Root component state we needed to pass the Button component a function handler This function handler gives the Button component access to the incrementCounter method on the Root component The Button's component onClick event function can now send the parent incrementCounter method the increment value that it should use Your challenge now. Try to customize the button component a bit more. Make it receive an operator as a prop, so we can for example make it multiply the result with its value instead of incrementing it. Let's support the 3 operations, adding, subtracting, and multiplying
So we can pass the button an operator property, and let's do plus for the 1, multiply for the 5, and subtract for the 10. This value we pass to the button is no longer an increment, so we should rename this now. I'll call it operand. Similarly, since we're not just gonna be incrementing the counter now let's rename this method into updateCounter instead. Names are important, always update the names of your variables to reflect the changes you're making to the logic. In the button component, we'll use the new operator and operand props to display the label and we'll make the onClick handler report both of them up the updateCounter method. The update counter now receives both operator and operand. and it should decide what to do with the operand based on the operator. Let's define a property on the Root instance, call it supportedOperations. This property will be an object indexed by the supported operator. every value will be the function that we should execute for that operator. The function receives the current counter and the operand value and returns the result of doing the operation on the counter. Now in update counter, we define the newCounter value. We first pick the supported function from the supportedOpreations object. Then we invoke that function with the current value and the passed in operand value. We'll then update the state with the newCounter value. You can test that now.
If you have any feedback about this lab, whether it's about the tool you used here, or the content, or anything else, good or bad, please let's me know. Email me or tweet to me directly, you can also join our slack chat at slack.jscomplete.com If you liked this. Please share it to help us get to a bigger audience. Thanks for taking the lab. See you in the next one.