如何将函数传递给自己的反应上下文提供程序,让您编辑状态?
Posted
技术标签:
【中文标题】如何将函数传递给自己的反应上下文提供程序,让您编辑状态?【英文标题】:How pass a function into an own react context provider which lets you edit the state? 【发布时间】:2020-01-10 11:07:01 【问题描述】:我有以下代码:
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()
function
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
中的那样更新。我怎样才能防止这种情况发生?实现这一点的设计模式是什么样的?
【问题讨论】:
把整个代码,不是sn-ps,是addNumber
调用在组件函数体中吗?
没错,它们位于自定义 NumberProvider 组件内部的组件函数体中
请更新您的问题,显示整个代码,预期的行为是什么,为什么它在函数体中?你想计算渲染次数吗?详细说明。
【参考方案1】:
因为useState
的设置器是异步的,所以一个调用会覆盖另一个调用:
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;
);
正如 cmets 中所讨论的,您应该使用 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>
)
【讨论】:
使用功能性useState
,也尝试解释一下你想要做得更好的地方,没有更多信息很难提出建议
我真正想要实现的是在我的应用程序中为 toasts(通知消息)创建一个消息队列。祝酒词应该被推入队列并在一段时间后被删除。我想通过上下文 api 从代码中的任何地方推送它们。在另一个地方,我想映射队列并显示当前在此队列中的所有消息。
这是我的实际代码库:github.com/blicc-org/blicc/blob/master/app/src/common/context/…,我的主要问题是我的自定义上下文提供程序中的 useState 似乎没有正确更新
你应该使用 useEffect
的副作用并从那里的队列中删除。
我更新了答案,请参考How do I ask a good question?以上是关于如何将函数传递给自己的反应上下文提供程序,让您编辑状态?的主要内容,如果未能解决你的问题,请参考以下文章