React Context 不随状态更新

问题描述

我有这样的代码

const ToastContextProvider: React.FC = ({ children }) => {
  const [toasts,setToasts] = useState<ToastDeFinition[]>([]);

  const addToast = useCallback(
    (toast: ToastDeFinition) => {
      if (toasts.find(({ id }) => id === toast.id)) {
        return logger.warn('Attempted to add a new toast with a duplicate ID!',{
          toast,});
      }

      setToasts((toasts) => [...toasts,{ ...toast }]);
    },[toasts]
  );

  const removetoast = (id: string) => {
    setToasts((toasts) => toasts.filter((toast) => toast.id !== id));
  };

  const value = {
    addToast,removetoast,};

  return (
    <ToastContext.Provider value={value}>
      <ToastPortal toasts={toasts} />
      {children}
    </ToastContext.Provider>
  );
};

这个想法是我会在一个组件中调用 addToast,其中 toast 是一个像这样的对象;

{
    id: 'test',message: 'Hello world',}

如果 ID 存在于 toasts 状态中,则不允许使用。但是,在 addToast调用 console.log(toasts) 总是记录一个空数组,并且 arr.find() 检查总是返回 undefined as结果,允许添加重复的 toast。

ToastPortal 会收到更新后的状态值。

Sandbox

解决方法

addToast 添加到您的 useEffect 的依赖项数组,以便关闭当前 addToast 值的最新 toasts 函数参与您的间隔逻辑。一个空的依赖数组意味着在开始时创建的 addToast 被重复调用,并且该方法关闭了 toasts 的初始值 []

  useEffect(() => {
    const interval = setInterval(() => {
      addToast({
        id: "test",msg: "testmsg"
      });
    },5000);

    return () => clearInterval(interval);
  },[addToast]);