useState
- set操作并非立即生效,而是保存在队列中,在下次render时依次调用。state更改后,会触发组件的重新刷新。
const add = () => {
setCount((c) => c + 1)
console.log('2--count', count) // 此时count为旧值,setCount要到下次render才生效
}
-
大部分场景下set中传入值和函数是无区别的,react会保证在下次用户操作前,相应state已经被更新;如用户点击按钮时数字加1,在某次点击后,react会确保下次点击前,本次点击的加1操作已经完成。
-
state可以为对象和数组,但需要注意把state当成只读对待,不要直接修改对象的键值,而是使用新对象替换旧对象。 直接修改state的键值不会触发re-render。
部分库支持使用直接修改对象键值的方式替代旧对象,如Immer
-
当state初始值的计算消耗较大时,使用初始化函数进行初始化,因为初始化函数只会调用一次。
-
当组件key为state时,state更新后,组件会重新进行初始化,其内部变量会重置
export default function App() {
const [version, setVersion] = useState(0);
function handleReset() {
setVersion(version + 1);
}
return (
<>
<button onClick={handleReset}>Reset</button>
<Form key={version} />
</>
);
}
function Form() {
const [name, setName] = useState('Taylor');
return (
<>
<input
value={name}
onChange={e => setName(e.target.value)}
/>
<p>Hello, {name}.</p>
</>
);
}
-
react在next state与current state相同时做了优化,不进行组件的更新。判断相同的方法是:Object.is。 这也是为什么不能直接修改对象和数组键值的原因,因为无法被Object.is检测出来更新了。
-
开发模式 & 严格模式下,组件函数、state的初始化函数和set函数会执行两遍,便于帮助开发者发现代码问题,避免mutation change,保持组件为pure。
function TodoList() {
// This component function will run twice for every render.
const [todos, setTodos] = useState(() => {
// This initializer function will run twice during initialization.
return createTodos();
});
function handleClick() {
setTodos(prevTodos => {
// This updater function will run twice for every click.
return [...prevTodos, createTodo()];
});
}