如何将函数传递给自己的 React 上下文提供程序,让您可以编辑状态?
How pass a function into an own react context provider which lets you edit the 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>)
}
如果我现在像这样通过提供程序中的上下文 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
的设置器是异步的,一个调用会覆盖另一个:
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>
)
}
我有以下代码:
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>)
}
如果我现在像这样通过提供程序中的上下文 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
的设置器是异步的,一个调用会覆盖另一个:
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>
)
}