ShouldComponentUpdate in functional components

I have a question regarding React shouldComponentUpdate (if not overwritten). I prefer clean, functional components, but I'm afraid that it is updated every time, even if the props / status has not changed. Therefore, I am considering using the PureComponent class.

My question is about this: Do functional components have the same shouldComponentUpdate as PureComponents? Or is it updated every time?

+15
source share
3 answers

In React, functional components have no state and no life cycle methods. Stateless components are an elegant way to write React components without a lot of code in our kit. But internally stateless components are placed in a class without any of the optimizations currently in use. This means that stateless and state components have the same code path inside (although we define them differently).

But in the future, React may optimize stateless components, as stated here:

In the future, it will also be possible to optimize performance for these components, avoiding unnecessary checks and memory allocation. [Product Details ...]

shouldComponentUpdate

Here you can apply our own optimizations and avoid unnecessary re-rendering of components. Using this method with various types of components is explained below:

  • Stateless Functional Components

    As stated earlier, stateless components do not have lifecycle methods, so we cannot optimize them with shouldComponentUpdate . But they are already optimized differently, have a much simpler and more elegant code structure, and cost less bytes than a component with all the lifecycle hooks.

  • extend React.PureComponent

    Starting with React v15.3.0 , we have a new base class called PureComponent can be extended with the PureRenderMixin built-in PureRenderMixin . Under the hood, a shallow comparison of current details / states with the following details / states in shouldComponentUpdate .

    However, we still cannot rely on the PureComponent class to optimize our components to the desired level. This case of anomaly occurs if we have details with Object types (arrays, dates, simple objects). This is because we have this problem when comparing objects:

     const obj1 = { id: 1 }; const obj2 = { id: 1 }; console.log(obj1 === obj2); // prints false 

    Therefore, superficial comparisons are not enough to determine if things have changed or not. But use the PureComponent class if your details are just a string, a number, a boolean .., and not objects. Also use it if you do not want to implement your own optimizations.

  • expand React.Component

    Consider the above example; if we know that the objects have changed, if the id has changed, then we can implement our own optimization by comparing obj1.id === obj2.id This is where we can extend our usual base class Component and use shouldComponentUpdate so that shouldComponentUpdate compare specific keys.

+10
source

The functional component will be redrawn every time the parent displays it, regardless of whether the details have changed or not.

However, using the high-order React.memo functional components can get the same shouldComponentUpdate that is used in PureComponent https://reactjs.org/docs/react-api.html#reactmemo.

You can simply wrap your functional component in React.memo when exporting, as shown here.

So

 const SomeComponent = (props) => (<div>HI</div>) export default SomeComponent 

Maybe instead

 const SomeComponent = (props) => (<div>HI</div>) export default React.memo(SomeComponent) 

example

The following example shows how this affects rendering.

A parent component is just an ordinary functional component. It uses new reaction handlers to handle some state updates.

It just has some tick state that serves only to give some hint about how often we redefine props, while it causes a re-rendering of the parent component twice per second.

Next, we have a clicks state that tells us how often we clicked a button. This is what we send to children. Therefore, they should ONLY review if the number of clicks changes, if we use React.memo

Now notice that we have two different kinds of children. One is wrapped in memo and the other is not. Child that is not wrapped will be redrawn each time the parent redraws. MemoChild packed MemoChild will be redrawn only when the click property changes.

 const Parent = ( props ) => { // Ticks is just some state we update 2 times every second to force a parent rerender const [ticks, setTicks] = React.useState(0); setTimeout(() => setTicks(ticks + 1), 500); // The ref allow us to pass down the updated tick without changing the prop (and forcing a rerender) const tickRef = React.useRef(); tickRef.current = ticks; // This is the prop children are interested in const [clicks, setClicks] = React.useState(0); return ( <div> <h2>Parent Rendered at tick {tickRef.current} with clicks {clicks}.</h2> <button onClick={() => setClicks(clicks + 1)}> Add extra click </button> <Child tickRef={tickRef} clicks={clicks}/> <MemoChild tickRef={tickRef} clicks={clicks}/> </div> ); }; const Child = ({ tickRef, clicks }) => ( <p>Child Rendered at tick {tickRef.current} with clicks {clicks}.</p> ); const MemoChild = React.memo(Child); 

You can check the example here https://codepen.io/anon/pen/ywJxzV

+7
source

Another approach is to use useMemo to update values ​​only when updating the observed values:

 const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]); 

In the case of objects, it is possible to use the status hook to cache the value of a variable of interest after it is updated. For example, using lodash :

 const [fooCached, setFooCached]: any = useState(null); if (!_.isEqual(fooCached, foo)) { setFooCached(foo); }'). const showFoo = useMemo(() => { return <div>Foo name: { foo.name }</div> }, [fooCached]); 
0
source

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


All Articles