Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
449 views
in Technique[技术] by (71.8m points)

reactjs - shouldComponentUpdate in function components

I have a question regarding React's shouldComponentUpdate (when not overwritten). I do prefer pure, function components, but I am afraid that it updates every time, even though props/state did not change. So I am considering using the PureComponent class instead.

My question regarding that: Do function components have the same shouldComponentUpdate check as PureComponents? Or does it update every time?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

A functional component will rerender every time the parent renders it, no matter if the props have changed or not.

However, using the React.memo high order component it is actually possible for functional components to get the same shouldComponentUpdate check which is used in PureComponent https://reactjs.org/docs/react-api.html#reactmemo

You can simply wrap your functional component in React.memo on export like shown here.

So

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

Could instead be

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

Example

The following example show how this affects rerenders

The parent component is just a regular functional component. It is using the new react hooks to handle some state updates.

It just have some tick state which only serves the purpose of giving some clues on how often we rerender a prop, while it forces a rerender of the parent component twice a second.

Further we have a clicks state which tell how often we have clicked the button. This is what the prop we send to the children. Hence they should ONLY rerender if the number of clicks changes if we use React.memo

Now notice that we have two different kind of children. One wrapped in memo and one which is not. Child which is not wrapped, will rerender every time the parent rerenders. MemoChild which is wrapped, will only rerender when the clicks 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);

Live Example (also on CodePen):

console.log("HI");

const Parent = ( props ) => {
  const [ticks, setTicks] = React.useState(0);
  const tickRef = React.useRef();
  tickRef.current = ticks;
  const [clicks, setClicks] = React.useState(0);
  
  setTimeout(() => setTicks(ticks + 1), 500);
  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);


ReactDOM.render(
  <Parent />,
  document.getElementById('root')
);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.12.0/umd/react-dom.production.min.js"></script>

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...