前言
由于React的函数式组件使用起来方便(对比class组件),我将重点使用函数组件来运行开发。在这系列博客中,我将分享我所学到Hook系列API的知识。
Hooks系列主要分以下内容:
从简单示例开始
export default function App() {
const initValue = 0;
const [n, setN] = useState(initValue);
const add = () => {
setN(n + 1);
};
return (
<div className="App">
<button onClick={add}>+1,此时n:{n}</button>
</div>
);
}
上面定义了一个button,当点击时,n+1并更新视图。
useState用法
const [state, setState] = useState(initValue) useState接收一个初始值,这个初始值可以是对象,也可以是简单数据类型。
在初始渲染期间,返回的状态 (state) 与传入的第一个参数 (initValue) 值相同。
返回的setState是一个函数,它接收一个新的 state 值并将组件的一次重新渲染加入队列。
规则
只能React函数组件中使用Hooks。
useState不能在内部的循环、条件判断、嵌套的方法中使用。
setState异步更新
接上面的代码
export default function App() {
const initValue = 0;
const [n, setN] = useState(initValue);
const add = () => {
setN(n + 1);
+ console.log(n)
+ setN(n+1)
+ console.log(n)
};
return (
<div className="App">
<button onClick={add}>+1,此时n:{n}</button>
</div>
);
}
点击之后视图上只加了1,但是log了两次,说明setN是异步的,不能立即更新,而是把所有同步代码执行完之后,再执行视图更新,而这时候入参的n还是旧的值,并没有被更新。
注:这时候传入的 n 由于闭包的原因,所以拿到的是旧的值。比如刚开始 n 是0,调用两次 setN 后相当于设置了两次1。
在React 事件中,setState 确实是异步的,为了提高性能(每次 setState 都会重新执行 hooks 函数),所以相同的setState会进行合并。
setN传函数
setN是可以传递函数的,它的参数是旧的n,返回新的value
上面的代码如果修改成以下内容就有效
export default function App() {
const initValue = 0;
const [n, setN] = useState(initValue);
const add = () => {
+ setN((oldN) => {
+ console.log(oldN);
+ return oldN + 1;
});
+ setN((oldN) => {
+ console.log(oldN);
+ return oldN + 1;
});
};
return (
<div className="App">
<button onClick={add}>+1,此时n:{n}</button>
</div>
);
}
如果可以的话,推荐优先使用函数。
state可以是对象
当 useState 中的 state 为对象时,调用相应的 setState 有一些要注意的地方,useState 不会自动合并更新对象,你可以用函数式的 setState 结合展开运算符来达到合并更新对象的效果。
错误示例
export default function App() {
const initValue = { n: 0, m: 0 };
const [state, setState] = useState(initValue);
const addN = () => {
setState((state) => {
return { n: state.n + 1 };
});
};
const addM = () => {
setState((state) => {
return { m: state.m + 1 };
});
};
return (
<div className="App">
<button onClick={addN}>+1,此时n:{state.n}</button>
<button onClick={addM}>+1,此时m:{state.m}</button>
</div>
);
}
这里的state不会自动帮我们合并,所以需要我们使用...运算符来帮助我们手动合并。
正确示例
export default function App() {
const initValue = { n: 0, m: 0 };
const [state, setState] = useState(initValue);
const addN = () => {
setState((state) => {
+ return { ...state, n: state.n + 1 };
});
};
const addM = () => {
setState((state) => {
+ return { ...state, m: state.m + 1 };
});
};
return (
<div className="App">
<button onClick={addN}>+1,此时n:{state.n}</button>
<button onClick={addM}>+1,此时m:{state.m}</button>
</div>
);
}
总结
- useState返回一对数组,第一个值是初始值,第二个值state的setter方法
- 如果state是对象的话,需要我们手动合并
- setState时,可以传函数也可以传值,如果依赖于旧的state,最好使用函数的形式