📜 ⬆️ ⬇️

Entry into React Fiber architecture

Hi, Habr! I bring to your attention the translation of the article "React Fiber Architecture" by Andrew Clark .


Introduction


React Fiber - the progressive implementation of the key algorithm React. This is the culminating achievement of React's two-year research team.


Fiber's goal is to increase productivity when developing such tasks as animation, organization of elements on the page and movement of elements. Its main feature is incremental rendering: the ability to divide the work of the render into units and distribute them between multiple frames.


Other key features include the ability to pause, cancel, or reuse incoming DOM tree updates, the ability to prioritize different types of updates, and also to reconcile primitives.


Before reading this article, it is recommended that you familiarize yourself with the basic principles of React:



Overview


What is reconciliation?


Reconciliation is a React algorithm used to distinguish one element tree from another to determine the parts that need to be replaced.


An update is a change in the data used to draw a React application. This is usually the result of calling the setState method; the final result of the drawing component.


The key idea of ​​the React API is to think of updates as if they could lead to a complete drawing of the application. This allows the developer to act declaratively, and not worry about how rational the application will be from one state to another (from A to B, B to C, C to A, etc.).


In general, drawing the entire application for each change only works in the most traditional applications. In the real world, this has a negative effect on performance. The reaction includes optimizations that create a full rendering view without affecting a huge amount of performance. Most of these optimizations include a process called reconciliation.


Reconcilement is an algorithm that is behind what we used to call the “Virtual DOM”. The definition sounds something like this: when you render a React application, an element tree that describes the application is generated in the reserved memory. This tree is then included in the rendering environment - using the example of a browser application, it is translated into a set of DOM operations. When the state of the application is updated (usually by calling setState), a new tree is generated. The new tree is compared with the previous one to calculate and include exactly those operations that are needed to redraw the updated application.


Despite the fact that Fiber is a close implementation of the scanner, the high-level algorithm explained in the React documentation will be mostly the same.


Key concepts:



Reconcile vs rendering


The DOM tree is one of the environments that React can draw, and the rest can be attributed to native iOS and Android Views with the help of React Native (That's why Virtual Dom is a little inappropriate name).


The reason why React supports so many goals is that React is designed so that reconciliation and rendering are separate phases. The compiler, working, calculates which parts of the tree have changed, the renderer later uses this information to update the previously drawn tree.


This separation means that React DOM and React Native can use their own rendering engines when using the same scanner that is in React Core.


Fiber is a reworked implementation of the reconciliation algorithm. It has an indirect relation to rendering, while rendering mechanisms (renderers) can be changed to support all the advantages of the new architecture.


Planning is a process that determines when work should be done.


Work - any calculations that must be performed. Work is usually the result of an update (for example, a call to setState).


The principles of React architecture are so good that they can only be described with this quote:


In the current implementation, React passes the tree recursively and calls the rendering functions on the entire updated tree in one tick (16 ms). However, in the future, he will be able to cancel some updates to prevent frame jumps.
This is a frequently discussed topic regarding React design. Some popular libraries implement a push ("push") approach, where calculations are made when new data is available. However, React follows a pull approach, where calculations can be canceled when necessary.
A reaction is not a library for processing aggregated data. This is a library for building user interfaces. We think that it should have a unique position in the application to determine which calculations are appropriate and which are not at the moment.
If something is behind the scenes, then we can cancel all the logic associated with it. If data arrives faster than frame rate, we can integrate updates. We can increase the priority of work coming as a result of user interaction (such as the appearance of animation when a button is pressed) against less important work on the background (drawing new content loaded from the server) in order to prevent frames from jumping.

Key concepts:



The reaction currently has no significant planning benefits; update results for the entire subtree will be displayed immediately. Careful selection of elements in the React core algorithm to apply scheduling is a key idea of ​​Fiber.


What is Fiber?


We will discuss the heart of the React Fiber architecture. Fiber is a lower-level abstraction over an application than developers are used to counting. If you consider your attempts to see her as hopeless, do not feel discouraged (you are not alone). Keep searching and it will eventually give its fruits.


So!


We achieved that Fiber architecture’s main goal — to allow React to take advantage of the planning. Specifically, we need to be able to:



To do all this we first need to divide the work into units (units). In a sense, this is fiber. The fiber represents the unit of work.


To go further, let's go back to the basic concept of React "components as data of functions" , often expressed as:


v = f(d) 

With this it follows that the rendering of the React application is similar to a function call whose body contains calls to other functions and so on. This analogy is useful when you think about fibers.


The way in which computers basically check the program execution order is called the call stack. When the function is completed, the new stack container is added to the stack. This stack container is the work done by the function.


When working with user interfaces, too much work is done right away and this is a problem, it can lead to animation jumps and will look intermittent. Moreover, some of this work may not be necessary if it is replaced by the most recent update. At this point, the comparison between the user interface and the function diverges, because components have a more specific responsibility than functions in general.
The newest browsers and React Native implement APIs that help solve this problem:
The requestIdleCallback distributes the tasks so that the low-priority functions are called in a simple period, and the requestAnimationFrame distributes the tasks, so that the high-priority functions are called in the next frame. The problem is that to use these APIs you need to divide the rendering work into incremental units. If you rely only on the call stack, the work will continue until the stack is empty.


Wouldn't it be nice if we could customize the behavior of the call stack to optimize the display of parts of the user interface? Would it be great if we could interrupt the call stack to manipulate the containers manually?


This is the React Fiber calling. Fiber is a new implementation of the stack, customized for React components. You can think of one fiber as a virtual stack container.


The advantage of this implementation of the stack is that you can save the stack of containers in memory and execute then (and where) you want. This is a crucial definition for achieving planning goals.


In addition to planning, manual actions with the stack reveal the potential of such concepts as consistency (concurrency) and error handling (error boundaries).


In the next section, we will look at fiber structure.


Fiber structure


Specifically, the “fiber” is a JavaScript object that contains information about the component, its input and output.


The fiber is matched with the stack container, but it is also matched with the essence of the component.


Here are some of the important properties inherent in the "fiber" (This list is not exhaustive):


Type and key


The type and key serve the fiber as well as the React elements. In fact, when a fiber is created, these two fields are copied directly to it.


Fiber type describes the component to which it corresponds. For component composition, type is a function or component class. For service components (div, span), the type is a string.


Conceptually, a type is a function that can be traced by a stack container.


Along with the type, the key is used when comparing trees to determine if the fiber can be reused.


Child and relative (child and sibling)

These fields point to other fibers, describing the recursive structure of the fibers.


The fiber child matches the value that was returned due to a call to the component's render method. In the example below:


 function Parent() { return <Child /> } 

Parent Fiber Child is Child.


The relative (or neighbor) field is used in cases where render returns multiple children (a new feature in Fiber):


 function Parent() { return [<Child1 />, <Child2 />] } 

Child fibers are a single linked list at the head of which is the first child. So in this example, the child Parent is Child1, and the relatives of Child1 is Child2.


Returning to our function analogy, you can think of a child fiber as a function called at the end (tail-called function).


Wikipedia example:


 function foo(data) { a(data); return b(data); } 

In this example, the tail-called function is b.


Return value (return)


The returned fiber is the fiber to which the program should return after processing the current fiber. This is the same as return address stack stack.
This can also be considered the parent fiber.


If the fiber has several daughter fibers, the return of each daughter fiber returns the fiber that is the parent. In the example above, the return fiber for Child1 and Child2 is Parent.


Current and cached properties (pendingProps and memorizedProps)


Conceptually, properties are function arguments. The current properties of the fiber is a set of these properties at the beginning of execution, cached is the set at the end of execution.


When incoming waiting properties are equal to cached, this means that the previous fiber output can be reused without doing any calculations.


Priority of current work (pendingWorkPriority)


The amount of work that determines priority is displayed by fiber. The priority level module in React ReactPrioritylevel includes different priority levels and what they represent.


Starting with a NoWork exception, which is 0, the larger number determines the lowest priority. For example, you can use the following function to check if the fiber priority is greater than the specified level:


 function matchesPriority(fiber, priority) { return fiber.pendingWorkPriority !== 0 && fiber.pendingWorkPriority <= priority } 

This feature is for illustration purposes only; It is not part of React Fiber.


The scheduler uses the priority field to find the next unit of work that can be performed. We will discuss this algorithm in the next section.


Alternative (or pair)


Refreshing (flush) a fiber is to display its output on the screen.


Work-in-progress - a fiber that has not yet been built; in other words, it is a stack container that has not yet been returned.


At any time, the essence of the component has no more than two states for the fiber to which it corresponds: the fiber in its current state, the updated fiber or the fiber in development.


The current fiber is followed by the fiber being developed, and then, in turn, the fiber is renewed.


The next state of the fiber is created lazily with the cloneFiber function. Almost always when creating a new object, cloneFiber will attempt to reuse the alternative (pair) of fiber if it exists, while minimizing resource costs.


You should think of the steam field (or alternative) as an implementation detail, but it pops up so often in the documentation that it was impossible not to mention it.


The output is a service element (or a set of service elements); node-leaf React application. They are specific to each display environment (for example, in the browser it is a 'div', 'span', etc.). In JSX, they are denoted as lowercase tag names.


Outcome: I recommend to try the features of the new architecture React v16.0


')

Source: https://habr.com/ru/post/444276/


All Articles