Hello, and welcome to the React.js: Getting Started series, from onurdesk. All the examples we do in this series should work on any React version greater than 16.8. In this series, we’re covering the fundamentals of the React.js library.
I’ve written an article on jsComplete about the common problems learners usually face when working with the React.js library. Scan through this article quick and keep it for your reference when you run into a problem while taking this series. Also remember that you can always ask for help in the Comment tab available in this series page.
Onurdesk mentors watch these comment forums, but please be as descriptive as you can when you ask a question. Share your code, list any errors you’re getting, and share a screenshot if you can. And when sharing your code, don’t paste it here. This comment tool is not good for that.
I’m a big fan of starting with why?
So before you dive in and write your first React component, let me make sure that you know why committing to learning React is a very good thing that you’re doing. If you’ve already formed your opinion about React, you can skip this video.
What’s important to remember here is that React is small, and it’s not a complete solution. You will need to use other libraries with React to form solutions. React does not assume anything about the other parts in any full solution. It focuses on one thing, which is the second part of the definition, building user interfaces. A user interface is anything we put in front of users to have them interact with a machine.
React will take care of the how and translate our declarative descriptions, which we write in the React language to actual user interfaces in the browser. Of course, HTML itself is a declarative language, but with React, we get to be declarative for HTML interfaces that represent dynamic data, not just static content. Let’s go back to React being a library and not a framework, and let me answer this question.
How exactly is not being a framework a good thing? Frameworks serve a great purpose, especially for young teams and startups. When working with a framework, many smart design decisions are already made for you, which gives you a clear path to focus on writing good application‑level logic. However, frameworks come with some disadvantages as well.
For experienced developers working on large codebases, these disadvantages are sometimes a deal breaker. Let me name two of the important disadvantages about using a framework. Frameworks are not flexible, although some claim to be. Frameworks want you to code everything a certain way. If you try to deviate from that way, the framework usually ends up fighting you about it.
Frameworks are also large and full of features, and that makes them hard to customize for specialized cases. If you need to use only a small piece of a framework, you usually have to include the whole thing. This is changing today, but it is still not ideal. Some frameworks are going modular, which I think is great, but I am a big fan of the pure UNIX philosophy to write programs that do one thing and do it well.
And React follows this philosophy because it is a small library that focuses on just one thing, enabling developers to declaratively describe their user interfaces and model the state of these interfaces.
Here’s a summary of the reasons why I think React gained this massive popularity. Working with the DOM API is hard. React basically gives developers the ability to work with a virtual browser that is friendlier than the real browser.
The React team at Facebook tests all improvements and new features that get introduced to React right there on facebook.com, which increases the trust in the library among the community. It is rare to see big and serious bugs in React releases because they only get released after thorough production testing at Facebook. Most importantly, remember the one thing that React does exceptionally well.
React established a new language between developers and browsers that allowed developers to declaratively describe stateful user interfaces. This means instead of coming up with steps for the transactions on their interfaces, developers just describe the interfaces in terms of a final state, like a function.
When transactions happen to that state, React takes care of updating the user interfaces based on that. If someone asked you to give one reason why React is worth learning, this last one is the one. If you need to convince someone about React, you can send them to this article, which summarizes what we covered in this video. However, to keep the course short, I’ll stop babbling about the why and get you started on the what and the how next.
React’s Basic Concepts
In any programming language, we invoke functions with some input, and they give us some output in return. We can reuse functions as needed and compose bigger functions from smaller ones. React components are exactly the same. They receive certain input objects, and they output a description of a user interface. We can reuse a single component in multiple user interfaces, and components can contain other components.
However, you don’t really invoke a React component. You just use it in your HTML as if it was just a regular HTML element. Also, unlike pure functions, a React component can have a private state to hold any data that may change over the lifecycle of the component. This ties to the second concept about React, it’s nature of reactive updates. React’s name is a simple explanation for this concept. When the state of a React component, the input, changes, the user interface it represents, the output, changes as well.
This change in the description of the user interface has to be reflected in the device we are working with. In a browser, we need to regenerate the HTML views in the DOM tree. With React, we don’t need to worry about how to reflect these changes or even manage when to take changes to the browser. React will simply react to the changes in a component’s state and automatically update the parts of the DOM that need to be updated. The third concept about React is its virtual representation of views in memory.
Let’s go back to the concept of the component. A React component can be one of two types. It can be either a function component or a class component. Both types can be stateful and have side effects, or they can be purely presentational. You should learn them both, but prefer to use function components over class components because they’re really much simpler. Class components, however, are a bit more powerful. In this course, I’ll use a mix of these two types so that we can learn them both.
Within a component, the state object can be changed while the props object represents fixed values. Props are immutable. Components can only change their internal state, not their properties. This is a core idea to understand in React, and I’ll have many examples for you to bring it home. Okay, let’s talk about this syntax that looks like HTML, but is not really HTML.
Your First React Component
Let’s implement this simple React component, a button with a numeric label, and clicking that button increments it’s numeric label to count how many times the button was clicked. Ready to do that? Don’t worry, we’ll take it one step at a time. First, let me tell you about this interface that you see here.
Before you can create a React application, you’ll need to do some environment configurations, and that might be a bit overwhelming for someone who is just starting to explore. Before we go that route, we’ll use this interface that I especially created for this course. It will help you learn the React way without the complexities of configuring a ton of tools to have a React environment. This playground is a good first step for quickly exploring React, but it stops being useful once the size of your application grows.
This icon is coming from the React DevTools extension, which is something you should install right away, by the way. So if you don’t have this icon in your browser, pause the video right here and go Google for React DevTools extension and add the extension to your browser. Once the extension is active, relaunch the jscomplete playground and make sure the icon is showing up here.
The React DevTools extension allows us to inspect and interact with any React application on any website. Let’s inspect the jscomplete playground while we’re here. Open your browser’s DevTools. There should now be a new tab for React. This has been added by the React DevTools extension. You’ll see that the extension is showing up two nodes here. The weird one is the main component for the jscomplete playground React app.
You don’t see normal component names here because the code is minified, but you can still see the structure of the app and you can see the properties and state of every component in the DOM tree, and you can interact with everything here. For example, this editor area here can be resized by dragging the separator. And this UI state is managed with React. If you can find the component responsible for that, you’ll see how there is a state element that gets changed when the separator is dragged. You can even change this state directly from the DevTools and trigger the resize based on the new value.
How cool is that? Take a moment and familiarize yourself with this extension. It is going to be a great asset for you when you start writing React applications. Every video in this course will start with a URL at jsdrops.com. That will take you to the starting point of that video. This way you can start from the exact point where I am. And if you’re coding along in the video and you code did not work as expected at the end of the video, you can simply compare your code to the code available when you go to the next jsdrops URL in sequence. Here is the first URL.
If you go to jsdrops.com/rgs1.1, rgs is for React Getting Started, you should see the exact code that I now have on the screen. Make sure that works for you. When this code is executed, you should see a Hello React line in the display. Let me go over what is going on here. We have a simple React function component named Hello. It returns a div. This component has no input. It’s also a peer component, no state here. To display a React component in a browser, we need to instruct the ReactDOM library on how to do that.
The function designed to do that is ReactDOM.render, which takes in two arguments. The first is the component to render, in our case it is the Hello component. Look how I used it here as if it was just another DOM element with a self closing tag. The second argument to the ReactDOM.render function is the DOM element in the browser where we wish the React component to show up. In this playground, we’re using the mountNode display element.
Make sure this React preset is selected, and paste in here the JSX value that we’re testing in the playground. Babel compiles that into a call to the createElement function in the React top level API. That’s it. That’s the magic of JSX. You write what looks like HTML and Babel converts into React API calls. So in the good example we have here, the browser is not really executing this. Instead, it’s executing the following, React.createElement, and this takes many arguments. The first argument is the element to be created, in this case, a div. The second argument is any attributes this element will have, the div element has no attributes.
And the third argument is the child of that div element, in our case, it’s just the string Hello React! Let me add a few more here to make sure this is working, and go ahead and execute this. And check it out, it is working. You see this line in React applications, but the browser is really executing this line instead. And this is true here as well, this line is also JSX. In this case, the conversion would be React.createElement, and it is a hello element here, this is not an HTML element, this is a React element. And it also doesn’t have any attributes and it doesn’t have any children.
So this is the equivalent line in this case, and this will work as well. While you can totally use React this way, without JSX, it would be a lot harder to code and maintain. So let’s stick with JSX. Let’s now update this code to make it into the button counter example that I showed you at the beginning of this video. Instead of a Hello component, let’s name our component Button, uppercase B button. You’ll have to do this change to the function name and where we used it here in the JSX line, Button. Instead of returning a div, let’s make it return a button HTML element, lowercase button here.
Start that buttons label as TEST. Ctrl+Enter to execute, and you should see a button with a label of TEST. Now I intentionally rendered a button component and the button element in this example. This is to make you aware that the capitalization here is not optional. React has some rules here. A component name has to start with an uppercase letter, because if you don’t do that, React will think you meant an HTML element.
For example, if we named our React component lowercase b button and tried to render that here, React will just render an empty button element here, and it will really not use this function up here at all. This is a beginner mistake. Always name your components with an uppercase first letter. This rendered button here is not interactive yet. To make it so, we’ll need to introduce some state to this component. We’ll use the simple and powerful React hooks to do that in the next video.
Your First React Hook
Continuing with what we started in the previous video, the current code is available under this URL, and our component currently renders a stateless button. We now need to make the button increment a counter every time it’s clicked. We need a state object. To use a state object, react has a special function named useState. This is also globally available here in the playground. So we’re going to be invoking this function.
This is the same 0 that’s coming from the initial value we specified for useState. So any value initialized here will show up as the button’s label, but we’ll keep it as 0. Now to use the setCounter updater function, every time we click on this button, we need to introduce an event handler. This is going to look similar to the way we can do this with the DOM API.
We define an onClick attribute on the button element. This onClick attribute is also case sensitive. It has to be camelCase like this. And unlike the DOM version of the onClick, which receives a string, this react onClick attribute receives a function reference. So you always specify that inside curly braces as well. In here, we’re going to specify a function reference.
Let me create a dummy function here, function. I’m going to name it logRandom, and we’ll make this function console.log(Math.random). Very simple. To use this function as the onClick event handler, we pass in here the functions reference, its name, just like this. To see the console.log messages, we need to bring up the browser’s console here. And after executing this code, every time I now click on that button, the console will print a random value.
Note that when we passed in the logRandom function here, we did not invoke the function. This will not work. You just need to pass in the pointer to the function. You can also inline the function definition right here inside the curly braces. So, basically, you paste in the function definition, and this will work as well. We can make this more concise by using the new arrow function syntax, which can fit in a single line here, () =>, and then the body of the function directly after that. This highlighted part is an inline arrow function definition. We’re not invoking the function here.
We’re defining it and passing this new reference to the onClick prop. This will work as well. So now that we saw how to wire an onClick event, what we need to do to make the counter count is to use the setCounter updater function that we got from useState. So instead of console logging a random value here, I’m going to use setCounter, invoke that function, and the argument to setCounter will become the new value of counter here. So if we pass in counter+1 as the argument just like this and execute this code, then every time the onClick event is triggered now, the counter will be incremented, and you’ll see the button behaving as we wanted it to.
This useState function is called a hook in the react world. It is similar to a mix‑in or a module, but it is a stateful one that hooks this simple component into a state. What I need you to notice here is that to reflect the new value of the counter variable in the browser here, we did nothing.
React did. You’re going to need a few more examples to appreciate this power. So let’s add some more features to this basic example. Let’s make our UI show many buttons and make all the buttons increment a single counter. But before we do that, let me give you a quick challenge. Instead of a simple counter, change this component to start the button with a label of 5, then double that value on each click. Go ahead and try to make this simple change, and you can see my solution under this URL.
Your First One-way Data Flow
In the previous video, we made a simple stateful Button component that renders an HTML button element and increments its numeric label when that button element is clicked. We introduced the useState React hook to manage a counter state. Let’s improve this component. First, don’t use long lines like this.
They’re hard to read. So let me format this return value to make it more readable. There we go. Note how I used parentheses here, not curly braces. We’re not returning an object here. We’re returning a function call, remember, a React.createElement function call. Second Improvement. Instead of an inline function here, let’s create an official click handler function.
This new function has to be defined inside the Button component because it needs access to the counter and setCounter variables. You can use any name here, but it’s commonly named handleClick. We can just paste the code we had inline before here as the body of this function. And in the onClick attribute here, we pass a reference to handleClick. Make sure this is all good and the button is still incriminating. So far, we’ve only worked with one component. Let’s add more. Let’s split our one Button component into two.
We’ll keep the Button component to be just the incrementer, and let’s add a new Display component, which is going to just display the value of the counter. This new Display component is going to be a pure presentational one. It will not have a state of its own. That’s normal. Not every React component has to have a stateful hook. So to create a new component, we define a function named Display, and we’ll make it return some HTML element. For now, let me just put a placeholder div in here and execute.
Notice that this new Display component did not show up because I have not included it in the rendered element yet. I just defined it. Let’s include it. So remember to include a component, we need to use it like that. However, you can’t just add it here as an adjacent sibling to the Button element. This will not work. Question, why does that not work? And the answer is because each one of these elements get translated into a function call.
You have few options here to fix this problem. First, you can render an array of elements here and insert into that array as many React elements as you wish. This will work. This is usually a good solution when all the elements you’re rendering are coming from the same component in a dynamic way. It’s not ideal for the case we’re doing here. The other option is to make these two React elements the children of another React element.
For example, we can just enclose them in a div, create a div element, then render the Button and the Display inside this div element. The React API supports this. In fact, React has a special object. If you need to enclose multiple elements like this without introducing a new div parent, you can use React.Fragment. This will do exactly the same thing that the div did, but no new DOM parent will be introduced. This case is so common in React that the JSX extension has a shortcut for it. Instead of typing React.
Fragment, you can just have an empty tag. This empty tag, if supported in the environment, will get compiled to the React.Fragment version. For the case that we’re doing here, I think a div here is okay, so I’m going to keep that. Question, what can we do to make this better?
And the answer is we should really extract this code into its own component. This new component can have any name, but you can just use App here. Go ahead and try to create this app component on your own. Make it return this DOM and use it in the ReactDOM.render call instead of what we have. We take the section, create a new function, name it App, make this function return the exact DOM tree that we have down under.
And then in here, instead of all that, we can just render the App component just like that. Since we’re going to display the counter’s value in the new Display component, we no longer need to show the counter’s value as the label of this button. Instead, I’m going to change the label to just +1. Now we need to display the counter value as the message in the Display component. But we have a problem. We actually have two problems.
The first problem is that the counter is currently a state element in the Button component, and we need to access it in the Display component, which is a sibling of the Button component in the current tree. So this is not going to work. The state in a React component can be accessed only by that component itself and no one else. To make this counter state accessible to both sibling components, we need to lift it one level up and put it in their parent component, which is the App component that we just introduced.
We just move this useState line down to the App component right here. I’ll initialize the counter with a different value here to make sure things are working. The logic of this handleClick function will need to change. We will come back to that in a minute. Let’s just comment it out for now. Now that we have the counter state element in the App compartment, which is the parent of the Display component, we can flow some data from the parent to the child. In this case, we need to flow the value of the counter state into the Display component, which brings us to the mighty props object. We haven’t really used it yet, so let me tell you about it.
To pass a prop to a component, you specify an attribute here, just like in HTML. You can name the props of the component anything you want. For example, I’ll make the Display component to receive a prop named message, and the value of that message is the counter variable that’s coming from the useState hook. The Display component can now use its props object, which is the argument to the function here, and it’s usually named props. You don’t really have to name it props, but that’s the convention.
All function components receive this object even when they have no attributes. So the Button component is currently receiving its props object, and that object so far has been empty. Because a component can receive many attributes, this props object will have a key value pair for each attribute. This means to access the message prop and place its value within the display div, we do curly braces and use props.message.
Let me test that real quick, and we have an error, handleClick is not defined because we’ve used it here and commented it out here. So let me just put an empty function here to get things working, and here we go. A counter value of 42 is now getting displayed. This is coming from the Display component. And what we did here is called the one‑way flow of data. Parent components can flow their data down to children components. Parent components can also flow down behavior to their children, which is what we need to do next. In the App component, since the counter state is here now, we need a function on this level to handle updating this state.
Let’s name this function incrementCounter. The logic for this function is actually the exact same logic that we had before in the handleClick function in the Button component. So we can just move it in here. This new function is going to update the App component’s counter state to increment the counter value using the previous counter value. The onClick handler in the Button component now has to change. We want it to execute the incrementCounter function that’s in the App component, but a component can only access its own functions. So to make the Button component able to invoke the incrementCounter function in the App component, we can pass a reference to incrementCounter to the Button component as a prop.
Something very powerful is happening here. The onClickFunction property allowed the button to invoke the App component’s incrementCounter function. It’s like when we click that button, the Button component reaches out to the App component and says hey parent, go ahead and invoke that incrementCounter behavior now. In reality, the App component is the one in control here, and the Button component is just following generic rules.
If you analyze the code as it is now, you’ll realize how the Button component has no clue what happens when it gets clicked. It just follows the rules defined by the parent and invokes a generic onClick function. The parent controls what goes into that generic behavior. That’s basically the concept of responsibility isolation. Each component here has certain responsibilities, and they get to focus on that. Look at the Display component too.
From its point of view, the message value is not a state. It’s just a value that the App component is passing to it. The Display component will always display that message. This is also a separation of responsibilities. As the designer of these components, you get to choose the level of responsibilities. For example, if we want to, we can make the responsibility of displaying the counter value part of the App component itself and not use a new Display component for that, but I like it this way.
This App component has the responsibility of managing the counter state. That’s an important design decision that we made, and it is one you’re going to have to make a lot in a React application, where to define the state. And the answer is usually simple, down in a tree as close as possible to the children who need to access that value on the state.
One of the selling points about components is reusability, making a component generic enough so that we can reuse it in different cases. Let’s do that. Let’s make the Button component more generic. Let’s assume that we can pass in an increment value here, and the Button component will use that value instead of the hard coded one. So we’ll use the more generic Button component to create a +1 button, a +5 button, and so on.
We need to upgrade this +1 here to something dynamic. It will be a property of the component, the amount to increment, and we’ll pass it down from the parent. Let’s name this new attributes increment, and the value we need to pass here is a number. Since the value here is not a string, we’ll need to use a set of curly braces here as well. So, for example, we can pass in 5. One quick note about this syntax here.
We could pass the number like this, but the Button component in this case will see and work with that value as a string. So don’t do that. Keep it this way so the Button component receives it as a numeric value, not a string. To use this new increment prop, we can just access it here as props.increment. There we go. We’ve got a +5. So let me go ahead and add a few more buttons here and use increment values of 1, 5, 10, and 100.
Let’s initialize this back to 0. And there we go. The UI rendered four buttons now with different labels, but they’re not going to work yet. In fact, all of them would still increment with a +1 at this point because we did not change their handlers. So the challenge now is to make each button increment the globally displayed counter by its increment value, not just 1. Do you think you can do that on your own? Give it a try. I saved the code as of now for you under 1.5 here. Here’s how I’d solve this challenge.
This incrementCounter function here will now need to receive an increment value, and we can use its argument to do that. So receive incrementValue in here, and instead of using +1 we’ll use the new incrementValue. Now we can invoke the incrementCounter function with different values. The incrementCounter function is aliased as onClickFunction for the button. So the Button component needs to invoke the onClick function with an argument now, which is its own increment value, and that can be accessed using props.increment.
So let me go back to handleClick and put this new logic inside handleClick, just like that. Make sure this is still working, and all is good. This is the final code of this example, and I saved it here under 1.6 for you. Through this example, we’ve touched on the many basic React concepts, but this is still a relatively simple example. Let’s build something a bit more useful next. But first, I need you to absolutely understand the value you’re getting from using React’s tree reconciliation under the hood That’s the next video.
Tree Reconciliation in Action
We can just add an input element like this, and it will render. We can do the same in React by adding more arguments after the third argument for React.createElement. To match what we did in the native HTML node, we can add a fourth argument here that is another React.createElement call that renders an input element. This input element has no attributes and no children. There we go. Okay, not too bad so far. Let’s add another node to both trees.
To add the timestamp in the React version, we add a fifth element to the top‑level div element. This new fifth element is another React.createElement call. This time it’s a pre tag as we used in the HTML version, no attributes as well, and the new date String for content. Both the HTML and React versions are still rendering the exact same HTML in the browser. But as you can see, the React way is a lot more complicated than the native DOM way.
So let me ask you the question again. Why go for all this trouble? What is it that React does so well that is worth giving up the familiar HTML and having to learn a new API to write what can be simply written in HTML? The answer is not about rendering the first HTML view. It’s about what we need to do to update any existing views in the DOM. So let’s do an update operation on the DOM that we have so far. Let’s simply make the timestamp tick every second.
When we refresh the display area, the timestamp string should be ticking every second in both versions. We are now updating our user interface in the DOM, and this is the moment when React will potentially blow your mind. If you try to type something in the text box of the HTML version, you will not be able to. This is very much expected because we are basically throwing away the whole DOM node on every tick and regenerating it. However, if you try to type something in the text box that is rendered with React, you can certainly do that.
Although the whole React rendering code is within our ticking timer, React is changing only the timestamp text and not the whole DOM node. This is why the text input was not regenerated and we were able to type in it. You can see the different ways we are updating the DOM visually if you inspect the two DOM nodes in the Chrome DevTools elements panel. The Chrome DevTools highlight any DOM elements that get updated. You will see how we are regenerating the entire first mountNode element with every tick, while React is smartly only regenerating the content of the pre element in the second mountNode.
In this example, the difference was the content of the pre element. React will then instruct the browser to update only the computed diff and not the whole DOM node. No matter how many times we regenerate our interface, React will take to the browser only the new partial updates. Note that the HTML version can be easily changed with a few more lines to make it update only the content of the pre element as well instead of the whole thing.
But that requires some imperative programming. We’ll first have to find the element that needs changing in the DOM tree and add some more imperative logic to change its content. We are not doing that in React. We’re being declarative in React. We just told React that we’d like a pre element with the date string. No imperative logic is here, and yet we’re still getting the efficiency of a tuned‑up imperative alternative. This is the subtle power here.
The React way is not only a lot more efficient, but it also removes a big layer of complexity about the way we think about updating user interfaces. Having React do all the computations about whether we should or should not update the DOM enables us to focus on thinking about our data and state and the way to model that state. We then only manage the updates that’s needed on the state without worrying about the steps needed to reflect these updates in the actual user interface in the browser because we know React will do exactly that for us, and it will do it in an efficient way.
Browsers do not have to deal with JSX. The input for a component is a set of properties you can access inside the component with its first argument object, which is usually named props, and also a set of state elements that a component can hook into with the special useState function. A component state can be changed inside that component, and every time a component changes its state, React rerenders it.
The props of a component cannot be changed by the component, but the whole component can be rerendered with different props by the component’s parent. The syntax to mount a React component in the browser is ReactDOM.render, and that takes two arguments, the component to render and the HTML element to hold the React‑rendered markup. React also comes with normalized events that work across all browsers in a standard way.