How Does React Actually Work? React.js Deep Dive #1

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
So, how does React actually work? We all know we can create React components using JSX and then render them on the web using React DOM or in a mobile app using React Native. We also have access to incredible features like the state or the component lifecycle and finally it is all extremely fast and flexible, but what is actually happening behind the scenes? In this video, we will go over the basic concepts that make React what it is. We will focus on reconciliation and rendering, the virtual DOM, the React Diffing algorithm and much more. So, let’s get to it. First, we have to understand the difference between React components, elements and component instances. Let’s start by taking a look at a simple component. I think this should be very familiar to you. For us, it is a React component that returns some React elements using JSX, the JavaScript XML. But for React, the return value is an object that looks like this. If you want to check for yourself, you can just log it to the console. When we call the component, we get the real return value. So, what exactly is happening? First, the JSX gets converted to many React.createElement function calls. Then, each of them returns the appropriate object. The fact that JSX gets converted to the React.createElement functions is the reason why we always have to import React when using JSX. Now, let’s take a close look at the return value. In our case, it is object that represents the root element, a div. The div is a type property, which corresponds to an HTML element. We can also see the key and ref properties, which are both null, because we haven’t provided any of them. There are also the familiar props and they contain all of the children. In our case, it is a simple text of “App component”. I previously mentioned a function called React.createElement and you might wonder how does it look like in practice. Well, let’s just head over to babeljs.io/repl and here, I will pass in the App component. Then, on the right side, we can see the converted code. We can see the React.createElement function being called with some arguments. The first argument is the element type, the second one are the props and the third argument are the children. Now, just so we are sure how it works, let’s take a look at a slightly more complicated component. We can once again see the type div, but the props are a bit more interesting. They contain a className of “App” and two children. The first is an image with source and className props and the second is a heading with the text of “App component”. By now, you might already have a few questions. First, why isn’t the key and the ref part of the props? Well, they are special properties and we will examine them further in the video. Second, what in the world is the $$typeof property? Well, it is just a security measure and if you want to learn more, there is a link in the description to an article about it. Now, we should have a good understanding of what a React element is. So, what is a React component? Well, a React component is a class or a function that outputs an element tree. If it is a function, the output is the return value of the function, and if it is a class, the output is the return value of the render method. Not only do React components have an output, they also have an input, which we all are familiar with – the props. All of this might seem very easy and obvious to you, but this is where it gets tricky. Just before a while, I showed you what the output is when we call a component. But we don’t really call them in our code, do we? We just add them to the JSX like this. So, what is the output of this? Let’s once again check that using console.log Well, it looks like a React element, but it is kind of weird. The type is some sort of a function and well, that is actually our component. When we render our component in the JSX, React is in fact calling it behind the scenes. If it is a function, React calls it directly with the assigned props and if it is a class, React creates a new instance of the class and calls its render method. So not only can React elements describe a DOM node, they can also describe a component, more precisely a component instance. But what is a component instance? When a React element describes a component, React keeps track of it and creates a component instance. Each instance has state and lifecycle and those instances are in fact very familiar to us. In functional components, we can access the state and the lifecycle using React Hooks and in class components, we make use of predefined methods and the “this” keyword, which refers to the individual component instance. The same way React calls our components, it also manages our instances by mounting and unmounting them. So now, we should have a pretty good knowledge of React elements, components and component instances. Now, it’s time to move to reconciliation. We know that all React does is create a tree of elements. This process is extremely fast, because as we saw, elements are just plain JavaScript objects and we can basically create thousands of objects in an instant. All of this is happening, when we call the render method. React generates this tree of elements by starting at the very top and recursively moving to the very bottom. If it encounters a component, it calls it and keeps descending down to the returned React elements. React keeps this tree of elements in memory, it is called the virtual DOM. The next thing to do is to sync the virtual DOM with the real DOM. On the initial render, React has to insert the full tree into the DOM. Making those kinds of adjustments to the DOM is very expensive, but on the initial render, there is no way around it. But what if the tree changes? What if there is a state change which results into a different return value and different elements? React once again very quickly generates a new tree of elements and we now have two trees – the old one and the new one. Now, it has to once again sync the virtual DOM containing the new tree with the real DOM. It would be very inefficient to re-render the whole tree, because as I said, making changes to the DOM is quite demanding. And this is why Reacts takes the old tree and finds the smallest number of operations to transform it to the new tree. It uses an algorithm called the Diffing algorithm in order to do that, diffing, because the goal is to differentiate the trees. Under normal circumstances, this is would be very difficult. For example, if we had one thousand elements, it could take up to one billion operations, which is not realistic. React instead manages to do that in a number of operations smaller than the number of elements. So, for one thousand elements, the number of operations will be smaller than one thousand. This is incredibly fast and it is possible only because of two very important assumptions. Let’s talk about those now. First, it assumes that two different types of elements will produce two completely different trees. You might be looking at this and saying “But isn’t this obvious?” and, generally speaking, not so much, but in the context of a React application, we can safely assume that two different element types will indeed result in two very different trees. The second assumption is simpler. React assumes then when we have a list of child elements, which we make changes to, we will provide the key and we will provide it in the right way. Let’s take a look at an example. Say we have a list of items that we map over and we have to provide unique keys. The first idea you might have is to provide keys using indexes, but this is one of the infamous bugs that I’m sure most of us came across at some point. This leads to unexpected functionality and it shouldn’t be surprising at all. We know that keys should always stay the same. Therefore, if we add a new item to the list to the very beginning, the keys will all increase by 1 which is wrong. This is why we provide keys using ids or simply unique properties. Previously, I mentioned that you may wonder why key isn’t part of the props. Now, you should understand why – key is unlike any other property. It is an important part of the very core of React – the Diffing algorithm. Now, let’s take a look at some of the basic operations that are part of the Diffing algorithm. Let’s say we have two elements at the same position with different types. In this case, React will just build a new tree from scratch, because of the first assumption. This means that all component instances in the old tree are destroyed along with their current state. We say that the components unmount. What if we have two elements at the same position with the same type, but with different attributes? React simply updates those attributes. The instances stay the same and the state is maintained. Let’s move to changing children. Imagine a list of names. What if we add a name to the end of the list? React first compares the first items and recognizes that they are the same. Then, it notices that the third item is new and just inserts it. But what if we add a name to the start of the list? In this case, React compares the items at same positions and notices that they are all different, so it basically generates a new tree. But this isn’t what we want. If we have ten thousand items and add a new one to the start, we don’t just want to generate a new tree. What we can do is provide keys. Using keys, we tell React which elements are still the same and which are new. Once again, this is why we can’t use index as a key. So that’s reconciliation. Now, let’s move to the rendering itself. This is where packages like React DOM and React Native come into play. We call those packages renderers. React on its own is just a library that allows us to define components and elements and it also does the diffing part. It isn’t platform specific and doesn’t take care of the rendering. Most of the actual implementation lives in the renderers. Renderers begin the reconciliation process. They generate the tree of elements and insert it wherever it has to be inserted. This is why they are a different package. When we use React for web development, React basically doesn’t even know that the elements end up in a web browser. React is therefore compatible with any renderer and you can in fact create your own using the react-test-renderer package. Once again, just to emphasize, React on its own only gives us the means of expression, so we can define components and so on, and it also does the diffing part. When you think about this, it may appear quite weird to you. In terms of web development, we usually only import React DOM once and call its render method. So how can most of the implementation live in the renderer package? The key to understanding this is to know that React communicates with the renderer. There are many ways of React doing that, but let’s explore one of them, the setState function. So, how exactly does setState work? setState is part of class components and the answer is that every renderer sets a special field on the created class. This field is called updater. When we use React on the web, it is React DOM that sets this field right after creating an instance of the class. Internally, it looks similarly to this. First, an instance of the class component is created and afterwards, we can see that the updater field is indeed being set to something that is part of React DOM. Then, whenever we call setState, a function similar to this one gets called. Here, a method called enqueueSetState of the updater field is called. Now, it should be quite clear how React communicates with the renderers. We could talk about state and the enqueueSetState method, but it is very complicated and is more of a topic for another video. What about React hooks? React hooks basically do the same thing, however, instead of an updater field, they use a dispatcher object. Internally, it looks similarly to this. We can see that when we call useState, the call is forwarded to something called currentDispatcher. And this dispatcher is once again set by React DOM. Whenever we render a component, React DOM sets the dispatcher similarly to this. This time around, the component is called, because it is a function. So, this is how React communicates with the renderers. And that’s all I wanted to talk about in this video. We’ve learned about React elements, components, component instances, reconciliation, rendering, the virtual DOM, the Diffing algorithm and its two very important assumptions. We’ve also learned about the ways React communicates with its renderers and peeked at a little bit of the internal code. There are many, many more things we could talk about and we could in fact go into much more detail, but I don’t want this video to be too long. My plan going forward is to create a video about React state and also another one about React hooks, where we will explore how they work behind the scenes. If you want to learn how to use React hooks, I’ve just recently finished a series where I covered each of the React hooks in detail. Let me know in the comments what kind of content would you like to see in the future. If you enjoyed the video, be sure to leave a like and subscribe to see more videos like this in the future. Thank you very much for watching.
Info
Channel: Philip Fabianek
Views: 128,752
Rating: undefined out of 5
Keywords: react, react.js, react js, what is react, how does react work, how does react work under the hood, how does react render, how does react work internally, how does react js work, react under the hood, understanding react js, react behind the scenes, react element, react components, reconciliation, react reconciliation, react diffing algorithm, virtual dom react, virtual dom in react js, virtual dom explained, react rendering explained, react internals, virtual dom, yt:cc=on
Id: 7YhdqIR2Yzo
Channel Id: undefined
Length: 15min 25sec (925 seconds)
Published: Mon May 03 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.