官方文档:使用 State Hook
语法:
const [state, setState] = useState(initialState);
类型声明:
type BasicStateAction<S> = (S => S) | S;type Dispatch<A> = A => void;export function useState<S>(initialValue: (() => S) | S,): [S, Dispatch<BasicStateAction<S>>] {const dispatcher = resolveDispatcher();return dispatcher.useState(initialState);}
说明:
state)与传入的第一个参数(initialState)值相同。setState 函数用于更新 state。它接收一个新的 state 值并将组件的一次重新渲染加入队列。useState 返回的第一个值将始终是更新后最新的 state。⚠️ 注意:
setState 函数的标识是稳定的,并且不会在组件重新渲染时发生变化。这就是为什么可以安全地从 useEffect 或 useCallback 的依赖列表中省略 setState。如果想基于先前的 state 进行 setState 变更数据,可以将更新函数传给 setState,该函数的第一个参数就是先前的 state,返回值就是变更后的 state。
代码示例:
如果你的更新函数返回值与当前 state 完全相同,则随后的重渲染会被完全跳过。
⚠️ 注意:
与 class 组件中的 setState 方法不同,useState 不会自动合并更新对象。你可以用函数式的 setState 结合扩展运算符或 Object.assign来达到合并更新对象的效果。
setState((prevState) => {// 也可以使用 Object.assignreturn {...prevState,...updateValues,};});
useReducer 是另一种可选方案,它更适合用于管理包含多个 property 的 state 对象。
说明:
initialState 初始化参数只会在组件的初始渲染中起作用,后续渲染时会被忽略state 需要通过复杂计算获得,则可以传入一个函数,在函数中计算并返回初始的 state,此函数只在初始渲染时被调用:const [state, setState] = useState(() => {const initialState = someExpensiveComputation(props);return initialState;});
调用更新函数 setState 并传入当前的 state 时,React 将跳过子组件的渲染及 effect 的执行。(React 使用 Object.is 比较算法来比较 state)
需要注意的是,React 可能仍需要在跳过渲染前渲染该组件。不过由于 React 不会对组件树的 深层节点 进行不必要的渲染,所以大可不必担心。如果你在渲染期间执行了高开销的计算,则可以使用 useMemo 来进行优化。
param 这个变量对于 DOM 而言没有影响,此时将他定义为一个异步变量并不明智。好的方式是将其定义为一个同步变量。
利用闭包,我们只要在这个模块中定义个变量,并且在函数组件中访问,那么闭包就有了。
export default function AsyncDemo() {const [param] = useState<Param>({});const [dataList, setDataList] = useState<ListItem[]>([]);function fetchDataList() {listApi(param).then((res) => {setDataList(res.data);});}function searchByName(name: string) {// 直接修改状态param.name = name;fetchDataList();}return [<div>data list</div>,<button onClick={() => searchByName('John')}>search by name</button>,];}