Hooks-useState

与 UI 更新相关的状态才使用 state 。如果只想要一个数据持久化,请使用 useRef

使用

1
const [state, setState] = useState(initialState);

如果初始的 initialState 需要通过复杂计算获得,则可以传入一个函数。

1
2
3
4
const [state, setState] = useState(() => {
const initialState = someExpensiveComputation(props);
return initialState;
});

伪代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function SM() {
let state = null;
return function myUseState(value) {
state = state || value; // 第一次调用没有初始值,因此使用传入的初始值赋值

function dispatch(newValue) {
state = newValue;
// 假设此方法能触发页面渲染
// render()
}

return [state, dispatch];
};
}

异步还是同步

useState 返回的 setCount 和 class 组件的 this.setState 一样,在事件处理函数内部执行的是异步的,在执行之后并不能获取到最新的值。

怎么获取最新的值

如果新的 state 需要通过先前的 state 计算得出,可以将函数传给 setState。该函数接收先前的 state,并返回一个更新后的值。

1
2
3
4
5
6
7
8
const [count, setCount] = useState(0);

useEffect(() => {
setCount((prevCount) => prevCount + 1);
setCount((prevCount) => prevCount + 1);
setCount((prevCount) => prevCount + 1);
// 注意,这里不能获取到count最新值
}, []);

如果需要使用最新的 state,可以在 useEffect 里获取到
当触发更新的函数(即setCount)接收一个函数时,会创建对应的update。这里调用了 3 次就会有 3 个update。所以count为 3。

为什么返回值是个数组

数组解构时,变量可以命名为任意名称,取值由它的位置决定。

1
2
const [state, setState] = useState(null);
const [state2, setState2] = useState(null);

对象解构时,变量必须与属性同名才能取到正确的值。

1
2
const { state, setState } = useState(null);
const { state: state2, setState: setState2 } = useState(null);

如果使用返回的是对象,当代码块中多次使用 useState 时,对象属性得重命名才不会冲突。相比之下数组代码显示的简洁。

但数组也有不足之处:

  • 返回值必须按顺序取
  • 返回参数较多时,又不是所有返回值都需要的情况下,写法会比较奇怪。例如只使用 setState: const [, setState] = useState(null)

避免不必要的 useState

案例来自波神的文章: https://mp.weixin.qq.com/s/nR9zczAZ5WZb1oG7w5cJDA
截取文章的其中一段:

Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×