本文已参与「新人创作礼」活动,一起开启掘金创作之路。
初始值
- 初始值只在第一次渲染的时候获取
const [count, setCount] = useState(0);
- 可以接受一个值,也可以接受一个函数
const [count, setCount] = useState(() => {
return 1;
});
不会覆盖
和Class的setState不同,hooks的setState对每个状态都是单独存储的,不会覆盖所有状态,可以同时存在多个state, 每次更新只需要更新各自的state就可以
异步更新的问题
使用setState多次更新时,我们很容易会发现一个问题,当我们setState时如果是在异步的语句中,这个用来计算的值,是当前的值还是上次计算还没回来值。
function App() {
const [count, setCount] = useState(() => {return 21;});
const handleClick = () => {
setTimeout(() => {
setCount(count + 1);
},2000)
};
console.log(count);
return (
<div>
<button onClick={handleClick}>{count}</button>
</div>
);
}
可以发现连续打印两次执行的结果,count依然是1? 这个就是因为,第二次执行时,由于setState(count + 1)更新,是取count当前的值去计算,当前就是点击的时候值,当前的count仍然是0,通过0计算,依然是1。
那如何解决异步问题呢?
setState可以接受一个函数作为参数,函数接收一个参数,这个时候的取值,是每次到执行的时候(2s后)才会去拿的值,就可以得到正确的值了
function App() {
const [count, setCount] = useState(() => {return 0;});
const handleClick = () => {
setTimeout(() => {
setCount((count) => {
return count + 1;
});
}, 2000);
};
console.log(count);
return (
<div>
<button onClick={handleClick}>{count}</button>
</div>
);
}
不释放内存
一般来说,函数执行完会释放里面变量的内存,但是hooks中的变量占据的内存不会被释放掉,所以一些没有必要用state的值,没有多次更新,只是取值进行计算的话,是可以减少一些useState的使用。
实现一个简单的useState
只是简单实现以下,不严谨,没有实现,setState和initialState可以接受函数的功能,也没有实现独立存储,不会释放内存等等功能,只是简单实现了更新和取值的功能。
const _states = []; // 假设为存储state的集合
const index = 0; // 假设用这个确保每个state的唯一性
function _useState(initialState) {
index++;
_states[index] = _states[index] || initialState || undefined;
const _setState = (newState) => {
_states[index] = newState;
render();
}
return [_states[index], _setState];
}