Code logic reuseIt is an important factor for us developers to reduce code duplication and code optimization. Last time, our students shared aboutVueFramework of the relevant logic reuse method and principle, this period we come to understandReactThe framework of logic reuse, involvingmixins.HOC.render props.HookFour parts, from simple to deep, welcome to exchange and study.

1 mixins

1.1 introduction of mixins

React Prior to V15.3.0, React. CreateClass created components that supported mixins. After V15.3.0 (inclusive), mixins were deprecated by creating components through classes.

1.2 Mixins Demo (based on V15.2.1)

The demo is pretty simple, so I won’t go over it here.

Tips: An analogy to Vue’s mixins.

1.3 Source code analysis of mixins

Based on 1.2 Demo and debugger debugging, I drew the following basic React-related class diagram and call relationship.The blue part is the core mixins flow, which is simply:

  1. React.createclass (spec) receives the spec parameter to determine whether the spec object has mixins attributes.
  2. If you don’t, great, just traverse the spec to mount propTypes, componentWillMount, event methods, etc., to Constructor. Prototype. This Constructor is the react component instance Constructor.
  3. If so, we need to determine whether there are mixins attributes in the mixins object (because the framework allows mixins to nest mixins), do not go back to Step 2 to mount mixins to the prototype, and continue step 3 to iterate if so.

Step 2 Mount the prototype, which will undergo react merge policies, such as mixins, propTypes, etc. We can define multiple internal implementation method merge calls. Render function is only allowed to define once, exceeding the limit will directly error message, more can be viewed source code to understand

1.4 mixins shortcomings

  • Implicit dependencies were introduced

For example, properties defined by nested mixins may be implicitly referenced by multiple nested mixins, and removing one breaks the other, does not form a hierarchy, is flattened, and runs in the same namespace.

  • Cause naming conflicts

Potentially disruptive changes exist because methods with the same name may already exist on some of the components that use it.

  • Resulting in snowballing complexity

Originally, common mixins were removed for code reuse, but as business requirements were iterated, differentiation gradually emerged and if was added to them. Else logic, code coupling degree, complexity, with the resulting cost of understanding and development error costs, refactoring code is also a problem.

Mixins Considered Harmful

2 HOC

2.1 introduction of HOC

Official introduction:

HOC is an advanced technique used in React to reuse component logic. HOC itself is not part of the React API; it is a design pattern based on the composite features of React.

Specifically, a higher-order component is a function that takes a component and returns a new component.

2.2 HOC Demo (based on V15.3.0)

Two common application scenarios of high-level component (HOC) are property proxy and reverse inheritance. Since the application understanding of reverse inheritance is not too deep, only the operation of property proxy is demonstrated here.

The Demo component can be understood as a common base component. The Hoc function definition returns an EnhancedComponent, which abstracts the props age property. EnhancedComponent is the EnhancedComponent of the Demo. Of course, you can continue to abstract public properties and methods upward with EnhancedComponent as a public component.

Tips: Can be compared to vUE’s higher-order components

2.3 HOC source code analysis

Based on 2.2 Demo, the following basic react-related class diagrams and call relationships are drawn.

Simple understanding:

  1. Code executedconst EnhancedComponent = Hoc(Demo)As you can see from the browser, EnhancedComponent becomes a Class HOC class and inherits the React Component
  2. When code execution encounters JSX syntaxconst comp = <EnhancedComponent />When, the React.createElement() method is called to convert it to the React Element object node, as shown below:
  3. When the code executesReactDOM.render(comp, document.getElementById("root"))Render calls reactmount. render and returns the React Component. Reactmount. render executes HOC’s render function. When JSX syntax is encountered, the return will perform step 2 to convert to react Element, and then execute the Render function of the Demo component. When JSX syntax is encountered, the return will perform Step 1 to convert to React Element, and finally render to the page through the complex rendering process.

2.4 HOC shortcomings

  • Logic is difficult to reuse, resulting in a deep component tree

If you use HOC or render props schemes to reuse state logic between components, it’s easy to create “nested hell.”

  • The business logic is scattered across the components’ methods
  • Hard to understand class

For those of you who are not front end majors, the cost of understanding class is a little bit higher

3 render props

3.1 Introduction to Render Props

Official introduction:

“Render Prop” refers to a simple technique for sharing code between React components using a prop with a value of function.

Components with Render Prop accept a function that returns a React element and calls it instead of implementing its own render logic.

Note: Render Prop is called Render Prop because of the mode, and you don’t have to use a prop named Render to use this mode. In fact, any function prop that is used to tell components what to render is technically called a “Render prop”

3.2 Render Props Demo (based on V15.3.0)

Here I define a Demo component that can accept the props func function and pass in the func function when using the Demo component externally, telling the component to render internally as h1 tags.

Tips: This usage is very similar to the slot slot in vue

3.3 Render props source code parsing

Simple understanding:

  1. When code execution encounters JSX syntaxconst comp = <Demo func={(name) => { return <h1>{name}</h1> }} />The createElement method in ReactElement. Js is converted to the ReactElement node.
  2. When the code executesReactDOM.render(comp, document.getElementById("root"))Reactdom. render is called and the React Component is returned. During render, the render function of the Demo component is called and JSX syntax is encounteredreturn (<div>{func(this.state.name)}</div>);Step 1 generates the element node and returns. When func(this.state.name) is executed, JSX syntax is encounteredreturn <h1>{name}</h1>, again perform Step 1 to generate the Element node and return, eventually rendering to the page through a complex rendering process.

3.4 Disadvantages of render props

Disadvantages are the same as HOC, nested hell, business logic scattered across components, and hard to understand classes.

The three logic reuse strategies mentioned above all have certain problems, so Hook is officially proposed.

4 Hook

4.1 introduction of Hook

Official introduction:

Hook is a new feature in React 16.8. It lets you use state and other React features without having to write a class.

4.2 Hook Demo (based on V16.8.0)

UseState, useEffect, useRef, useContext, as well as advanced useReducer, useMemo, useLayoutEffect and custom Hook methods.

Here, I will only demonstrate useState and useEffect

Tips: This is similar to the Vue3 Composition API

4.3 Hook source code analysis

In the actual debugger, the useState call is divided into two phases:

Declaration stage: In the process of rendering the page for the first time, a call to useState is triggered, which is also in the render phase of the Reconciler in the blue area in the picture below. This blue area is not the focus of this time, but it will be shared later

Const [count, setCount] = useState(0); Track useState all the way, and finally locate source code:

ReactCurrentDispatcher$1.current = nextCurrentHook === null ? HooksDispatcherOnMountInDEV : HooksDispatcherOnUpdateInDEV;
Copy the code

The detailed call diagram is shown below in blue:

Can see the stage statement: actual call useState HooksDispatcherOnMountInDEV object, then useState call the core of the final method – mountState

Call phase: When count is updated, the useState call is triggered when setCount is called.

You can see the call phase: Actual call useState HooksDispatcherOnUpdateInDEV object, and then useState again call updateState, ultimately calls the core method – updateReducer, Next, we will focus on the analysis of what the mountState and updateReducer methods in these two phases do.

Declaration phase -mountState

Source code screenshot is as follows:

The source code disassembly is shown in the figure below:

Simple understanding:

Create a hook object to hold the initial value and the dispatch function for easy data update during the call phase. When useState(0) is executed, actually mountState(0) is executed, initialState = 0 is assigned to memoizedState, [hook.memoizedState, dispatch] returns the destruct assignment to [count, setCount]. SetCount is also associated with an internally defined dispatchAction.

Call stage -updateReducer

Source code screenshot is as follows:

SetCount (count + 1) = setCount(count + 1)

MemoizedState; memoizedState; memoizedState; The initial value baseState, the last update of the dispatch function recorded in the queue, and the calculated value, and finally return [Hook. memoizedState, Dispatch], at which point the count value changes to 1.

4.4 Hook shortcomings

A few key official responses:

  • There are no plans to remove class, new code is recommended to try
  • It is not recommended to Hook an existing class
  • The goal is to cover all usage scenarios of class as early as possible
  • Will not replace render props and higher-order components

Then can you understand the two small disadvantages of Hook:

  • Refactoring is not recommended for older projects using classes; the real problem is older projects
  • Usage scenarios may not cover all scenarios of class

5 concludes

This paper analyzes four logic reuse strategies of React through introduction, demo use, source code analysis and disadvantages. In the process of learning, I also found the similarities and similarities between react and VUE frameworks in implementing logic reuse ideas, which was quite surprising. There are shortcomings in the article, welcome to point out more, share learning!