Initialize the

const [state, setState] = useState()
Copy the code

React guarantees that the setState function is immutable during rerendering, so it can be omitted from the useEffect or userCallback dependencies list

Lazy initialization

function Table(props) {
  // ⚠️ createRows() is called on every render
  const [rows, setRows] = useState(createRows(props.count));
  // ...
}
Copy the code
function Table(props) {
  // ✅ createRows() is only called once
  const [rows, setRows] = useState(() = > createRows(props.count));
  // ...
}
Copy the code

So let’s look at the difference between these two, the first one is function execution, which is equivalent to

const value = createRows(props.count);
const [rows, setRows] = useState(value);
Copy the code

So it is executed every time on re-render, but the value of rows is unchanged unless setRows is called; The second is the function definition, which is executed only once during initialization.

The second is lazy initialization, which avoids expensive computations repeated.

update

UseState doesn’t have a callback function like this.setState, so you can do something after making sure the state changes. But you can do that with useEffect.

const [value, setValue] = useState(0)

function () {
  setValue(newValue)
}

useEffect(() = > {
  // ...
}, [value])
Copy the code

If the update returns exactly the same value as the current state, subsequent rerendering will be skipped entirely. Use object.is to compare values.

Is setState asynchronous or synchronous?

Strictly speaking, neither asynchronous nor synchronous. SetState is sometimes not updated in real time because React is optimized to process updates in batches in the event handler. At some point, the setState is updated synchronously. Let’s look at the two cases separately.

batch

In the event handler, React processes updates in batches, such as

const onClick = () = > {
  this.setState({a: 1})
  this.setState({a: 2})}Copy the code

Components are only updated once

Updates in asynchronous code (promise, async/await, setTimeout/setInterval, fetch) are not processed in batches. For example:

const onClick = () = > {
  callAPI().then(() = > {
    this.setState({a: 1})
    this.setState({a: 2})})}Copy the code

When a component is updated twice, we call it outside of the React event handlers. When an update occurs outside of the React event handler, the callback occurs after the React execution is complete. React cannot be updated in batches.

So why is setState designed to be “asynchronous,” or batch?

The simple summary is to avoid multiple updates. If setState is synchronous, react will rerender multiple times when setState is called multiple times, some of which is unnecessary.

?? When setState is called multiple times, react is rerendered multiple times. Doesn’t it affect the execution of the logic after setState?

Don’t. When React calls setState asynchronously in the class component, it will first update the state, re-render, and then execute it in order according to the lifecycle. After the lifecycle is complete, it will continue to execute the logic after setState. However, in functional components, react executes the logic after setState and re-render (until another setState is encountered) and then executes the lifecycle. The differences are as follows: Class-based components

state = {
   a: 0.b: 0
 }

 componentDidMount() {
   setTimeout(() = > {
     this.setState({a: 1})
     console.log('a'.this.state.a)

     this.setState({b: 1})
     console.log('b'.this.state.b)
   }, 1000)}componentDidUpdate() {
   console.log('updated'.this.state.a, this.state.b)
 }

 render() {
   const {a, b} = this.state
   return <div>{a} {b}</div>
 }
Copy the code

Output: updated 1 0, a 1, updated 1 1, B 1 Functional component

  const [a, setA] = useState(0)
  const [b, setB] = useState(0)

  useEffect(() = > {
     setTimeout(() = > {
       setA(1)
       console.log('a')

       setB(1)
       console.log('b')},1000)
   }, [])

   useEffect(() = > {
     console.log('effect', a, b)
   }, [a, b])

   return <div>{a} {b}</div>
Copy the code

Output: effect 0 0, a, effect 1 0, b, effect 1 1

So how do you optimize for updates that can’t be batch updated?

  1. Integrate state into an object so that multiple updates become a single update
  2. You can manually force batch updates using an API provided by React.
promise.then(() = > {
  ReactDom.unstable_batchedUpdates(() = > {
    this.setState({a: true}); // Doesn't re-render yet
    this.setState({b: true}); // Doesn't re-render yet
    this.props.setParentState(); // Doesn't re-render yet
  })
  // When we exit unstable_batchedUpdates, re-renders once
})
Copy the code

React Event Handlers are included in unstable_batchedUpdates by default, so they can be updated in batches. Elsewhere you can force unstable_batchedUpdates, and when unstable_batchedUpdates ends, updates are refreshed to the interface. 3. useReducer