The Heart of React || How React works under the hood

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
Hi, I've finally gotten to the bottom of  one of the most interesting topics for me. This is how React works under the hood. Every day we use Hooks, Lifecycle, JSX,  Synthetic Events, and confidently talk   about the performance of our project. This confidence was generated by excellent  React documentation, and just a huge number of  hours spent writing projects on this technology. But the question is how well we understand  what is really going on inside React. how we get 60 frames per second even with a huge  number of interactive elements on the screen. That's why I chose React Reconciliation  as the first topic for this playlist. As a source of information, I used the official  React documentation and an article by Andrew  Clark, co-founder of the Redux. He presented similar speech at  the React Next 2016 conference. Andrew works for the React core team, therefore  there is definitely confidence in this material. All links will be in the description. I would start with a brief definition from the  article Reconciliation is the algorithm behind  what is popularly understood as the virtual DOM. Let's try to understand in  more detail how it works. It all starts with the basic unit, the node. From them, using a set of render methods, a  whole tree of react elements is assembled, which  describes the entire state of the  application and is stored in memory. And this tree is called current. Then this tree is fed into  the rendering environment. In the case of the web, this  This environment will transform   this tree into a set of DOM operations needed to render the current changes. It prioritizes DOM operations according to  the urgency of their getting to the user. When the website is first loaded, the rendering  environment renders the entire DOM tree, and  the user can finally see the first result of   all these manipulations and  can press the "Hi" button. Clicking the button leads to a change  in our website, and as a result,   a new tree is built, and it is called Work-in-Progress. Next, we compare the work-in-progress tree with  the current tree and calculate the difference  between them, and only the difference between  these trees is given to the rendering environment  and then the already familiar process  of turning the difference into a   set of DOM operations and prioritizing them. And as a result, these operations  will update the DOM tree of our   website and the user will finally see that the bruise greeted him. Oh yes, I almost forgot, the work-in-progress  tree becomes the current tree. This is a fairly general instruction describing  the mechanism of reconciliation, but it has  many interesting details. Let's try to go through some of them. For example, React core developers have divided  the tree comparison engine and the rendering  environment into separate phases, so that React  DOM and React Native can use their own rendering  engines when using the same comparison  engine that is in React core. The next point is to work with tree. There are several general solutions to the  algorithmic problem of transforming one tree into  another with a minimum number of operations. However, advanced algorithms have a  complexity of the order of O(n^3),   where n is the number of elements in the tree. If 1 ,000 nodes were mounted, this algorithm  would require a billion comparisons. This is too expensive. So React core developers chose a heuristic  algorithm of the order of O(n). With it, 1 ,000 nodes requires 1 ,000 comparisons. It sounds much more attractive. Let's figure out what a heuristic algorithm is. Heuristic is a technique designed for solving  a problem more quickly, when classic methods  are too slow, or for finding an approximate  solution, when classic methods fail to find any  exact solution. Raveli speaking, this algorithm is not effective  for all cases, and the React core team has  made several assumptions to  make this algorithm work. First, two elements with different  types will produce different trees. Second, the developer can specify which child  elements can remain stable between different  renderers using the key property, however, in  practice, these assumptions are true for most  of the cases. For example, in the following code, diff  is the parent and the counter is the child. And then there were updates, and we changed the  type of the parent element from diff to span and  the child remained the same component counter. Despite this, diff and span are different types,  and the entire tree starting from this element  will be unmounted and their state will  be destroyed and then mounted again. Let's think about what it means  for us as a React developers. For example, we have a pure component that  is responsible for displaying a picture. Perhaps it has some kind of logic, for example  checking for its presence in the browser cache. And if the cache doesn't include it, we need to  show a stubbed picture during the loading state,  or maybe some other logic inside. This component is used in  many places of the project. For instance, in an avatar. The user has the opportunity to  switch his avatar to the editing mode. It means that controls appear next to it. In our case, it is to delete the  picture or to upload a new one. Of course, we expect that when switching from  the avatar view mode to the edit mode, the image  component itself will not be updated because  it is a pure component and we pass the same   props to it. But it's not so simple. We need to wrap the image  component in an additional   diff in order to do absolute positioning  the controls on top of the  picture itself in the corner. As a result of switching the mode, the algorithm  begins to revise our components from top to  bottom. The first was a diff, and it remained. Then there was the image component,  and now again some kind of diff. So there was a change of types. This means that the past image component  is completely removed from the tree. It means ComponentWillOnMount is  called from the previous instance. And then the tree is rebuilt, which means that  a new instance is created for the image class. And RenderMethod and ComponentDidMount are  called, but we didn't count on it at all. To fix this problem, let's  just remove the extra diff. Let's say we figured out how to implement  it without the diff, and add only controls   and editing mode. In this case, it will really work. Our image component will not be  mounted and unmounted every time. But then, I decided to experiment and added  controls, not under the image, but above it. It is small changes, but again, the problem  returned with the fact that the image component  was unmounted and mounted when switching the mode. And it sounds logical, we again compare from top  to bottom, and see where the picture was, now  the controls, so it was defined as a change  in types, and again everything went wrong. At the same time, if you change the code a little,  and bring it to the form with single return,  and use a logical operator, then everything works. It works as now the place is reserved for boolean,  although it is not displayed to the user, or  for the controls, but the position of  the image component is always the same. But let's return to the case with two returns. To solve this problem, we can  use the second assumption. The developer can specify which  child elements can stay the same   between different renders using property key. It means if we specify the key property for the  image component, then React will know that the  position of the component has changed, and your  code will work again as you originally expected. And of course, the first thought was  to try to use the key and wrap the   editing case in an additional diff, but it doesn't work. Key works only within the  same depth level of nodes. Knowing these assumptions, you can easily solve  the problem with strange behavior at first  glance. But do not forget, thanks to this assumption,   React was able to speed up  the algorithm for traversing  the tree from the order of the O(n^3) to the O(n) order. And it is very important. The next very important thing that  was mentioned in this video is the   prioritization of DOM operations. This is really a very important and very  complex thing, because just think about it. We want the application not to lag,   as in games we expect 60 frames  per second for a smooth picture. To achieve it, you need to update  the frames every about 16 ms. Now   imagine that the user has made a 240 ms interface update. To prevent all this from starting to lag, the  React Core team decided to split the interface  update into smaller DOM operations, the  so-called units, and prioritize them. Because the hover animation of the button seems  to be a higher priority than updating data in  a block that is not even in  the viewport at the moment. Therefore, React sorted the  tasks for you and showed the   animation in the first frames and postponed some less prioritized tasks for the next frames. To implement this logic, the React team uses  two methods, requestAnimationFrame for higher  priority tasks that need to be performed literally  in the next frame, and requestIdleCallback  for low priority tasks that can be  performed while the application is idle. More details can be found at  the links in the description. As you see, the main difficulty of such a task  is to priorities these small DOM operations. You can even find a separate package  in React Repository called scheduler. If we open it, we will see  a field called scheduler   priorities.js, which includes priority constants, which we discussed earlier. As you can see, there is  an idle priority constant. It means this kind of task is performed  while the application is idle. There is a low normal priority and others. All this allows you to determine  the order of DOM operations. And if we go back and open the  scheduler.js file and scroll a little,   we will even see the timeouts of these priorities. The numbers look pretty high, as much as 10  seconds of waiting for low priority tasks. And let's scroll a little lower. There is, we see the timeouts returns  depending on the priorities of the task. But I'm not sure if this code is currently used  in production, or if it's just some drafts. Since we see prefix unstable  on many exported methods,   And if you search globally by the repository,  you will see that priority constants  is duplicated in several places. Probably, active work is still  underway to find the best solutions. The last point which I would like to talk  quite a bit is about the history of the React. In version 16, the long-awaited project called  Fiber was finally introduced into React, which  made it possible to plan which operations with  the DOM need to be performed now, which can be  postponed a little, and which are no longer  relevant at all and cannot be performed. and as a result, the user gets his  cherished 60 frames per second. This algorithm is, of course, much  more than just a React scale scheduler. It started as an experiment and was written from  scratch, and after two years it was merged into  the repository, which  personally made me very happy. I remember there was even  an own site with countdown   to the release of Fiber was introduced. What's it all about? This is an example where simple  migration of your project to a   newer version of the library can improve your project's performance. Therefore, it is always worth keeping an eye out  for new experiments from your favorite libraries  and perhaps you can benefit your current  project without spending a lot of money on it. If you liked this video, I will be grateful if  you press like button and subscribe to the channel  because this is not the last video and many  other useful things await you on our channel. Bye bye.
Info
Channel: AI Bruise
Views: 12,075
Rating: undefined out of 5
Keywords: IT, information technology, JavaScript, IT Bruise, Bruise, Software developer, react, virtual DOM, react reconciliation, react virtual DOM, Fiber, React Fiber, React DOM, React under the hood, how react works, React Core, React scheduler, How React works under the hood, AI Bruise, the heart of React, react tutorial, modern react, modern react tutorial, react tutorial for beginners, react for beginners
Id: 5XnU2cvgw5o
Channel Id: undefined
Length: 10min 31sec (631 seconds)
Published: Mon Jan 29 2024
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.