面试题答案
一键面试原因分析
在React中,状态更新是异步的。当在同一个事件处理函数内执行多个状态更新操作时,React会将这些更新操作合并,以提高性能。然而,React默认的批处理机制只在React自身的合成事件(如onClick
、onSubmit
等)和生命周期函数中起作用。如果在这些之外(如原生DOM事件、setTimeout
、Promise
等回调中)更新状态,批处理机制不会生效,导致状态逐个更新。
React的状态更新批处理机制
- 批处理的概念:批处理是指React将多个状态更新操作合并成一次更新,从而减少不必要的渲染,提高性能。
- 何时批处理生效:在React合成事件和生命周期函数中,React会开启批处理模式。在这种模式下,多个
setState
(类组件)或setState
(函数组件使用useState
)操作会被合并,只触发一次重新渲染。 - 何时批处理不生效:在原生DOM事件处理函数、
setTimeout
、Promise
等回调函数中,React不会自动开启批处理模式。此时,每一次状态更新都会立即触发重新渲染。
手动控制批处理以达到预期效果
- 使用
unstable_batchedUpdates
(React 18之前):- 在React 18之前,可以使用
unstable_batchedUpdates
函数手动开启批处理。这个函数接受一个回调函数作为参数,在回调函数内的所有状态更新都会被批处理。
import React from 'react'; import ReactDOM from'react-dom'; const App = () => { const [count1, setCount1] = React.useState(0); const [count2, setCount2] = React.useState(0); const handleClick = () => { ReactDOM.unstable_batchedUpdates(() => { setCount1(count1 + 1); setCount2(count2 + 1); }); }; return ( <div> <p>Count1: {count1}</p> <p>Count2: {count2}</p> <button onClick={handleClick}>Increment</button> </div> ); }; ReactDOM.render(<App />, document.getElementById('root'));
- 在React 18之前,可以使用
- React 18之后:
- 在React 18中,
unstable_batchedUpdates
已经被移除,取而代之的是自动批处理。无论在何种环境下(包括原生DOM事件、setTimeout
等),React都会自动开启批处理模式。但如果需要在某些情况下禁用批处理,可以使用flushSync
。
import React, { useState } from'react'; import { flushSync } from'react-dom'; const App = () => { const [count1, setCount1] = useState(0); const [count2, setCount2] = useState(0); const handleClick = () => { flushSync(() => { setCount1(count1 + 1); }); setCount2(count2 + 1); }; return ( <div> <p>Count1: {count1}</p> <p>Count2: {count2}</p> <button onClick={handleClick}>Increment</button> </div> ); }; export default App;
flushSync
会立即刷新React的状态更新,阻止批处理,确保在它内部的状态更新会立即生效,而不会与后续的状态更新合并。
- 在React 18中,