logoahooks dive
State

useSetState

用于更新对象状态的 Hook

用法

用于更新对象状态,自动合并对象。

{
  "hello": ""
}

源码

useSetState.ts
import { useState } from 'react';
import useMemoizedFn from '../useMemoizedFn';
import { isFunction } from '../utils';

export type SetState<S extends Record<string, any>> = <K extends keyof S>(
  state: Pick<S, K> | null | ((prevState: Readonly<S>) => Pick<S, K> | S | null),
) => void;

const useSetState = <S extends Record<string, any>>(
  initialState: S | (() => S),
): [S, SetState<S>] => {
  const [state, setState] = useState<S>(initialState);

  const setMergeState = useMemoizedFn((patch) => {
    setState((prevState) => {
      const newState = isFunction(patch) ? patch(prevState) : patch;
      return newState ? { ...prevState, ...newState } : prevState;
    });
  });

  return [state, setMergeState];
};

export default useSetState;

解读

重点就是 setMergeState 函数。

首先使用 useMemoizedFn 缓存函数引用,避免重复创建函数。

关于 useMemoizedFn,可以查看对应文档:useMemoizedFn

const useSetState = <S extends Record<string, any>>(
  initialState: S | (() => S),
): [S, SetState<S>] => {
  const [state, setState] = useState<S>(initialState);

  const setMergeState = useMemoizedFn((patch) => { 
    setState((prevState) => {
      const newState = isFunction(patch) ? patch(prevState) : patch;
      return newState ? { ...prevState, ...newState } : prevState;
    });
  });

  return [state, setMergeState];
};

内部直接调用 setState 函数,并传入一个回调函数。

const useSetState = <S extends Record<string, any>>(
  initialState: S | (() => S),
): [S, SetState<S>] => {
  const [state, setState] = useState<S>(initialState);

  const setMergeState = useMemoizedFn((patch) => { 
    setState((prevState) => { 
      const newState = isFunction(patch) ? patch(prevState) : patch;
      return newState ? { ...prevState, ...newState } : prevState;
    });
  });

  return [state, setMergeState];
};

如果 patch 是函数,则调用 patch 函数,并传入 prevState 参数,返回新的状态。否则,直接返回 patch

最后,如果 newStateTruthy 值,则返回使用扩展运算符合并后的新对象。否则返回 prevState

内部也没有对 prevStatenewState 进行类型判断,而是直接使用扩展运算符合并。如果得到的是非 object 类型,则会报错。这个需要特别注意。

Last updated on

On this page