In this article, we will explain how the react ecosystem works with three libraries and four major libraries, and the necessary source validation:
- react
- redux
- mobx
- react-router
The React reference version is V17.0.2
Before moving on, if you haven’t read this framework article, I suggest you take a look at it first, so that the concepts involved in the discussion will not be repeated.
This release mainly includes the first two chapters, and the rest will be completed in the future.
1 React Related concepts
React is a UI library that uses components to build interactive UIs that are updated as data changes.
1.1 the react getting modal
Let’s take a look at the initial design of React and get a feel for the step-by-step design process.
The first four steps below have complete code samples here, and the pseudocode for the remaining steps can be viewed by clicking the link above.
- conversion
React reduces the UI to a mapping of data to some other data. The same input should return the same output.
- Abstraction and composition
A complex UI cannot, of course, be represented by a simple function, so the UI can be abstracted into reusable pieces that can then be combined, using one function to call another.
- state
A UI is not just a copy of server-side data or business data, but a lot of data that represents snapshots of the state of specific scenarios in the application, such as typing in an input box or scrollbar position. Therefore, we tend to design the data model to be immutable, and the state can be deliberately updated through a top-level atomic operation. In the code example, callback is used to trigger re-rendering, which is not consistent with the actual react data update detection model. This proactive notification is called push, but actually it is pull.
- The cache
Calling the same pure function over and over again (a function with no side effects and whose results are only affected by parameters) is a waste of performance. Instead, create a cacheable version that saves parameters and results and does not need to be re-executed as long as the parameters remain unchanged.
- Logic and data separation
In real development, there are many places to manage these states. For reuse, we can use Currification, encapsulating business logic and then entering state.
- The list of
In many UIs, many lists are generated. To store these list items, you can maintain a map for saving, where key can be the unique ID of each item. When we need to store a lot of list items, we need to find a good caching strategy that balances frequency and memory usage. The good news is that UI lists generally don’t change very much, so we can use trees in the UI to store them (such as DOM trees or virtual DOM trees).
- Algebraic Effects
Sometimes we don’t want to pass each piece of data through one layer of abstraction (in this case, function calls that extend to one level of the abstraction tree), so we need a function that can be passed directly through at least two layers. This is called context in React. We can do this with the idea of Algebraic Effects, decoupling what you’re going to do and how you’re going to do it, and if you can’t get the data at the current level, give control to another logic that’s going to get the data, and then give it back to the logic that’s going to do it, What are Algebraic Effects? Algebraic Effects and its use in React.
1.2 Dive into the React programming model
Here’s a look at some of the concepts in React when running React as a UI.
- The host trees
React eventually outputs a tree that changes over time. This is called a host tree, such as a DOM tree, JSON objects, etc. They are part of the host environment. The nodes of the host tree are called host instances, such as a DOM node; These host instances have their own attributes, such as domNode.className; The hosting environment provides apis to manipulate these host instances, such as appendChild.
- The renderer
Renderers are used by React to manage host instances, such as the React DOM, which outputs virtual managed by React in memory to the corresponding host environment. Each renderer has an entry that specifies the output of the React element tree to the final host environment.
- The react elements
In the host environment, the host instance is the smallest building unit. In React, the react element is a common JS object that describes the host object. The React elements also form a tree to represent the entire UI, for example
// JSX is the syntactic sugar used to describe these objects. // <button className="red" /> // </dialog> 'dialog', props: { children: [{ type: 'button', props: { className: 'blue' } }, { type: 'button', props: { className: 'red' } }] } }Copy the code
- coordinate
When Render is called for the first time, React maintains a tree of React elements. When render is updated the next time, Render returns the latest tree. React needs to update the UI efficiently based on the differences between the two trees to keep the state and UI in sync. This process is called coordination, which is the focus of this article and will be covered in more detail later.
- component
In the previous section, react simplified the UI to a mapping of data to some other data. Functions whose output is a React element are called components. Functions that return components are also components.
- Inversion of control
Our component could be a function, such as Form, but we use
// 🔴 React does not know that Layout and Article exist. // Because you are calling them. Reactdom.render (Layout({children: Article()}), domContainer) // ✅ React knows Layout and Article exist. // React calls them. ReactDOM.render( <Layout><Article /></Layout>, domContainer )Copy the code
This gives react control and does the rest of the work.
- The cache
When the react component state changes, the default coordination triggers the entire subtree of setState. Some methods can save the previous coordination result, such as through react. Memo or PureComponent.
- Batch update
Data updates in React are asynchronous. After data updates such as setState are executed, the coordination is not triggered immediately, but batch updates are performed based on the internal scheduling mechanism
- Side effects
A side effect is when a function does something unrelated to its return value, such as fetching data or manually updating the DOM.
2 fiber architecture
This chapter reference
- React Fiber Architecture
- Inside Fiber: in-depth overview of the new reconciliation algorithm in React
- In-depth explanation of state and props update in React
- The how and why on React’s usage of linked list in Fiber to walk the component’s tree
- coordinate
2.1 reconciliation
Coordination is divided into two stages: Render and commit. The former is used to diff the difference between the two virtual DOM, and the latter renders the diff changes to the host environment. The diff algorithm in React is based on two assumptions
- Two elements of different types produce different trees
- The key attribute on the child element remains stable across different renders
Specific for
- For the root node
- When the root node is different, React takes down the original tree and creates a new one, destroying the original state.
- React keeps the nodes when the root nodes are the same, compares the updated attributes, and then diff recursively across the subtree
- For children
- If it is a list, that is, the child elements are the same, the key attribute should be added for reuse, and comparisons will be made in order
- For component elements, the instance reuses the updated state if the type is the same, otherwise it does not.
2.2 Why is the new architecture introduced
Before, we talked about the change detection in the front-end framework. When the state changes in the application, there are various diff algorithms for the two virtual DOM before and after. The optimization effect of this algorithm is limited.
In traditional implementations, virtual DOM’s diff is called a stack Reconciler, which is executed synchronously in the form of a stack of calls, without pauses in between, so that other work on the main thread can stall.
Therefore, fiber architecture is introduced here to optimize the DIff process by setting the render stage as incremental and dividing it into multiple frames if necessary to give sufficient time for some high-priority tasks such as animations.
2.3 What is Fiber
Fiber is a new data structure for the Virtual DOM, implemented in linked lists.
New data structure of the new architecture using their own design, a new data structure using Windows. RequestIdleCallback (), and the window. The requestAnimationFrame () will allow different priority work to achieve the purpose. In fiber architecture, fiber nodes are taken as units, and each unit is an execution unit.
2.4 The purpose of the Fiber Reconciler
Here is a summary of the purpose of Fiber
- Fragments interruptible tasks that can be reset or reused
- Ability to adjust priorities for different tasks
- Interlacing between parent and child elements to support layout in React
- Ability to return multiple elements in Render
- Better support error Boundaries
2.5 Concepts related to Fiber Reconciler
We use an example to illustrate the whole process, which can be demonstrated online here.
class ClickCounter extends React.Component {
constructor(props) {
super(props);
this.state = {count: 0};
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState((state) => {
return {count: state.count + 1};
});
}
render() {
return [
<button key="1" onClick={this.handleClick}>Update counter</button>,
<span key="2">{this.state.count}</span>
]
}
}
Copy the code
- React element to fiber node
We introduced react elements earlier, and each react element describes a host instance. Each React element in turn corresponds to a Fiber node, which holds some state of the component and dom. The React element is regenerated each time a component’s Render method executes, and fiber nodes may be reused.
Different types of React elements do different things. In this simple example, the ClickCounter component calls the lifecycle method, and the SPAN host component synchronizes the DOM. Each fiber node holds some work information that needs to be processed, so it can be considered a unit of work. The execution of this work can be tracked, scheduled, suspended, and cancelled.
When a Fiber node is generated from the React element, in addition to removing and reusing the fiber node corresponding to the react element (modifying the property if necessary), it is also moved at the same level based on the key property.
- fiber tree
The Fiber nodes form a tree, the aforementioned Virtual DOM, which looks like this in this case
Nodes in the tree are connected using the child, Sibling and return attributes, where child denotes the child node, sibling denotes the sibling node, and return denotes the parent node.
When first rendering react generates a fiber tree corresponding to the current UI. This tree is usually called current. When react changes the state, another tree is created to represent the next rendering. This tree is called workInProgress, and the two trees use alternate to refer to each other. All the work is done in the workInProgress tree, which can be thought of as a draft of the Current tree, where React processes all the components and then renders them to the screen in one go. It becomes the new Current tree when rendered to the screen.
We can see from the figure that the root node of the Fiber tree is hostRoot, which is mounted to fiberRoot as a current property, which can be obtained on the _reactrootContainer._internalRoot property of the container, for example
const fiberRoot = query('#container')._reactRootContainer._internalRoot
const hostRootFiberNode = fiberRoot.current
Copy the code
- Fiber node
Fiber tree nodes are FiberNode types. In addition to alternate, effectTag and nextEffect have the following properties
- The stateNode represents the component instance, DOM node, or React Element represented by the current node and is used to store the related state
- The function or class definition associated with the type node is an HTML tag if it corresponds to a DOM element, or a component instance or function if it is otherwise
- The tag defines the type of fiber node and determines what work this node contains
- UpdateQueue status updateQueue
- MemorizedState represents the last state rendered to the screen
- MemorizedProps represents the props rendered to the screen last time
- Key is used earlier to process the child elements of a list
- side-effects
In React, we can think of a component as a function that returns UI functions using state and props as arguments. Therefore, we can think of any side effects that are not related to react as side effects, such as synchronizing dom or calling lifecycle functions. Each fiber has an effectTag field to hold these side effects, and the side effects on each node are linked by firstEffect and nextEffect into a linked list called the Effects List, as in the Fiber tree
The linked list of side effects is
2.6 Details of the Fiber Reconciler
This is a continuation of the previous section (2.5). The reconciler is divided into render and COMMIT steps. The first step results in a Fiber tree marked side-Effects. This step is fiber’s main stage, asynchronously processing aspects that are not related to the UI, and is executed synchronously when first rendering. The second step is always synchronous, because the entire rendering process should be continuous and the user should not see the middle of the rendering process, which is mainly used to perform side effects such as updating the DOM, and the process ends. The two phases will also call the corresponding lifecycle functions, which are the hooks that mark the stages of the whole process, such as Git hook.
The details of coordination will be interpreted at the source stage, and the existing data are older and inconsistent with the actual implementation, so there is no need to go into details here.
2.7 priority
The React system has five priorities, the third by default
export const unstable_ImmediatePriority = 1;
export const unstable_UserBlockingPriority = 2;
export const unstable_NormalPriority = 3;
export const unstable_IdlePriority = 5;
export const unstable_LowPriority = 4;
Copy the code
3 Fiber source code
This will contain the entire coordination process for the latest version, including the source code for the first rendering and updates.
Let’s start with a few ready-made ones
- Analysis of the principle of [email protected]
- React Source code
4 hooks
Hook is another important update to React16 in addition to Fiber, which uses hooks to make functional components state.
reference
- Get into the React Hooks principle
- React hooks Hooks are linked to a list of hooks
- Under the hood of React’s hooks system
- UseEffect complete guide
- How is a functional component different from a class component?
5 Event System
React encapsulates its own event system over native events for browser compatibility and performance reasons.
reference
- React Works of the event system
- REACT event system and source code
- React events and the future
- React V17.0 RC release: No new features
6 Status Management
This section introduces redux and MOBx principles and their comparison
reference
- Mobx summary and the differences between Mobx and Redux
- Redux or MobX: An attempt to dissolve the Confusion
7 react-router
This section discusses the principles of react-Router
reference
- Understanding The Fundamentals of Routing in Reac
- reactjs routing
- React Router