A confused

As we all know, the React. Memo or the React.PureComponent is used as a way to optimize React performance. When props are unchanged, pure components do not cause rerendering. In theory, this optimization should be worth using globally. If we did that, we would go a step further and React would officially make all components “pure components” by default. But React didn’t actually do that. Why? This confusion started when I first started learning the React framework. I have asked a lot of old front-end, but have not received a good explanation, which has puzzled me for a long time, until recently I have my own answer.

Premise of discussion

If we are to discuss this issue, we first need to reach a consensus and a premise that the performance of ordinary components is slightly better than that of “pure components” for the same re-render. The reason is simple, because pure components require additional shallow comparisons of props. In addition, the React.memo requires additional execution to wrap into a higher-order component.

Does your “pure component” really have performance optimizations?

Based on the above premise, it’s easy to conclude that the benefits of using pure components come from avoiding unnecessary rerendering, and that if your component is rerendering every time, or if the developer fails to meet the rerender blocking conditions of pure components, the performance will be worse!

function TestA(props: React.PropsWithoutRef<{ count? :number, style? :any,
}>){
  return <div style={props.style}>{props.count || 0}</div>
}

export default React.memo(TestA)
Copy the code

Case 1:

function App() { // Top-level component
  const [count, setCount] = useState(0)

  return (
    <div className="App">
        <TestA count={count} />
        <div>{count}</div>
        <button onClick={()= > setCount(count => count + 1)}>+</button>
    </div>)}Copy the code

Example 2:

function App() { // Top-level component
  const [count, setCount] = useState(0)

  return (
    <div className="App">
        <TestA style={{color: 'red'}} / >
        <div>{count}</div>
        <button onClick={()= > setCount(count => count + 1)}>+</button>
    </div>)}Copy the code

Negative returns from using “pure components”

From these two simple examples, it is easy to conclude that “pure components” can not be used mindlessly and globally to improve performance, because using them incorrectly can lead to performance degradation. The React documentation is cautious about using “pure components” to improve performance.

If you give the React component the same props and state, and the render() function renders the same content, using the React.PureComponent can improve performance in some cases.

  • There are higher demands on developers

    Press no table.

  • Increased mental burden

    ShouldComponentUpdate () in react.pureComponent is only a superficial comparison of objects. If the object contains complex data structures, it is possible to produce incorrect alignment results because deep differences cannot be examined.

    Because “pure components” is only a superficial comparison to props, if we use “pure components” globally, we always have to be aware that each props object contains complex data structures, and that there might be deep data that could be updated individually causing rendering delays. In addition, over-reliance on “pure component” re-rendering rules can lead to unexpected errors.

    This approach exists only as a way to optimize performance. But don’t rely on it to “block” rendering, as this can be buggy.

Direction of component performance optimization

  • Use “pure components” only when necessary

    “Performance optimization is often ineffective until there is a performance problem.” This is a front-end development concept THAT I personally believe in. This is not to say that there is no need to do performance tuning, but that it should be targeted. Specific performance optimizations and mindless global optimizations require a higher level of technical understanding, because you need to solve a more specific problem. So instead of using “pure components” globally, it’s better not to use “pure components” globally. At the end of a project or when performance bottlenecks occur, you can optimize for components that cost more to render.

  • High cohesion, low coupling

    Ah, this is the eternal guiding principle of programming!

    In my work, I often find that some colleagues write more than 1000 or even 2000 lines of a component action, without any reusability, abstraction and modularity. You don’t have to look at the code to imagine that such a component must be extremely poor performance and difficult to maintain, because a state change causes an entire page to be re-rendered. From my own development experience, it is extremely rare for a component to be more than 200 lines long, and a properly abstracted component must not be verbose. The use of state boosts also requires considerable caution, as misuse of state boosts often means improved coupling and worse reusability. When each component is highly cohesive and decent, you will find a significant number of components that do not require parameter passing because state is managed within the component. Even if you don’t intentionally use “pure components”, most components will only naturally rerender when necessary!

Previous articles:

Hand-pull a drag-and-drop form generation low code tool called Leggo

How does the front end gracefully set up a non-invasive burrow

The front end also needs to understand the decoupling idea: from the IoC container to the DI implementation