javascript - 如何将函数传递到自己的 react 上下文提供程序中以允许您编辑状态?

标签 javascript reactjs react-hooks react-context react-state

我有以下代码:

import React, { useState } from 'react'

export const NumberContext = React.createContext()

export function NumberProvider({ children }) {
  const [numbers, setNumbers] = useState([])

  function addNumber(number) {
    const copy = [...numbers]
    copy.push(number)
    setNumbers(copy)
  }

  return (
    <NumberContext.Provider value={[numbers, addNumber]}>
      {children}
    </NumberContext.Provider>
  )
}
export function App() {
  return (
      <NumberProvider>
        <DisplayNumbers />
        <AlterNumbers />
      </NumberProvider>
  )
}
export function DisplayNumbers() {
  const [numbers, addNumbers] = useContext(NumberContext)

  return (<p>{numbers}</p>)
}

如果我现在通过提供程序中的 Context api 调用 addNumber() 函数,如下所示

export function AlterNumbers() {
  const [numbers, addNumber] = useContext(NumberContext)

  function alterNumbers(){
    addNumber(1)

    setTimeout(() => {
      addNumber(2)
    }, 3000)
  }

  return (<button onClick={alterNumbers}>)
}

numbers 等于 [2] 而不是 [1, 2]

我的提供程序函数 NumberProvider 中的状态不会像 NumberContext.Provider 中的状态那样更新。我怎样才能防止这种情况发生?实现这一点的设计模式会是什么样子?

最佳答案

由于 useState 的 setter 是异步的,因此一个调用会覆盖另一个调用:

const NumberConsumer = () => {
 const [numbers, addNumber] = useContext(NumberContext);

 addNumber(1);               // Will update numbers to [1] in "future"
 setTimeout(() => {          // Will update numbers to [2] in "future"
    addNumber(2);            // The call within the timeout,
                             // is not aware of the previous state
 }, 3000);

 return <h1>{JSON.stringify(numbers)}</h1>;
};

您应该使用functional useState:

setState(prevState => {
  // Object.assign would also work
  return {...prevState, ...updatedValues};
});

正如评论中所讨论的,您应该使用 useEffect 将逻辑更改为更健壮的内容:

export function ToastProvider({ children }) {
  const [toasts, setToasts] = useState([])
  const [key, setKey] = useState(0)

  function showToast(label, message) {
    setKey(key + 1)
    setToasts([
      ...toasts,
      {
        key,
        label,
        message,
      },
    ])
  }

  useEffect(() => {
    setTimeout(() => {
      const copy = [...toasts]
      copy.pop()
      setToasts(copy)
    }, 5000)
  }, toasts);

  return (
    <ToastContext.Provider value={[toasts, showToast]}>
      {children}
    </ToastContext.Provider>
  )
}

关于javascript - 如何将函数传递到自己的 react 上下文提供程序中以允许您编辑状态?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57841179/

相关文章:

javascript - 从 API 检索数组并在 React 中过滤

javascript - 使用 kefirjs 将数据传递给 React 组件

javascript - React 自定义钩子(Hook)重新渲染

javascript - 有没有办法更新云功能中的collectionGroup

javascript - Tampermonkey 脚本等待元素然后填充它们

Javascript 存储输出并下载文件

javascript - 我们如何使用 React Hooks 实现 componentWillUnmount?

javascript - 如何在循环执行时逐渐将内容附加到 div?

javascript - 路由获取参数和应用逻辑

javascript - 与 useEffect 一起使用时,自定义钩子(Hook)会被无限调用