Using multiple setHook makes component render more than once?

时间:2019-04-08 13:19:48

标签: reactjs react-hooks

If I have alot of useState and on the click of a button I call multiple setHook, does it renders multiple times or only once?

e.g.

export default function setMultipleHooks() {

    const [hook1, setHook1] = useState(false)
    const [hook2, setHook2] = useState(false)
    const [hook3, setHook3] = useState(false)
    const [hook4, setHook4] = useState(false)

    const setHooks = () => {
        setHook1(true)
        setHook2(true)
        setHook3(true)
        setHook4(true)
    }

    return (
        <button onClick={setHooks} >Hey</button>
    )

}

Once I click the button, how many times does it render? 1 or 4 times?

Normally to check how many times the component is rendering, I just put a console.log in the render method, but with functional components, I'm not sure how to test this.

If it renders 4 times, it would be better to use only one useState (passing an object) if the 4 hooks are always related?

2 个答案:

答案 0 :(得分:1)

React may batch multiple setState calls and render them all at once. And in your case it do that, because you're inside an event handler (onClick).

It renders only once (initial render not included) as you can see from the snippet below.

Github issue about React batching setState() calls

You can, nevertheless use an object with 4 properties instead of 4 state hook varibales. But you'll have to be careful when updating state, because hook's setState() doesn't auto merge your last state with your new state property. It completely replaces the state with the new object you're passing.

React Docs - Using the state hook

So you'd have to do something like this:

function YourComponent() {
  const INITIAL_STATE = {a: false, b: false, c: false, d: false};
  const [state,setState] = useState(INITIAL_STATE);

  function handleClick() {
    setState((prevState) => {
      return({
        ...prevState,
        b: true
      });
    });
  }

}

const { useState, useRef, useEffect } = React;

function App() {

  const renderTimes = useRef(0);

  const [hook1, setHook1] = useState(false);
  const [hook2, setHook2] = useState(false);
  const [hook3, setHook3] = useState(false);
  const [hook4, setHook4] = useState(false);
  
  const setHooks = () => {
    setHook1(true);
    setHook2(true);
    setHook3(true);
    setHook4(true);
  }

  useEffect( () => {
    renderTimes.current+=1;
  });

  return (
    <div>
      <div>I rendered {renderTimes.current} time(s).</div>
      <div>NOTE: The initial render is not included.</div>
      <div>State hook1 is equal to: {hook1.toString()}</div>
      <div>State hook2 is equal to: {hook2.toString()}</div>
      <div>State hook3 is equal to: {hook3.toString()}</div>
      <div>State hook4 is equal to: {hook4.toString()}</div>
      <button onClick={setHooks}>Click</button>
    </div>
  );
}

ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="root"></div>

答案 1 :(得分:1)

Normally to check how many times the component is rendering, I just put a console.log in the render method, but with functional components, I'm not sure how to test this.

Just put the console.log inside function (function itself is render method). It will render only once, because there is a small time interval within which if multiple calls to useState setter occur their updates will be batched.

If it renders 4 times, it would be better to use only one useState (passing an object) if the 4 hooks are always related?

If you have complex state you should really consider useReducer.


More:

https://stackoverflow.com/a/54716601/10995369

https://github.com/acdlite/react-fiber-architecture

相关问题