提问人:AntoninL 提问时间:10/17/2023 最后编辑:AntoninL 更新时间:10/17/2023 访问量:97
使用反应状态作为信号可以吗?[关闭]
Is it ok to use react states as signals? [closed]
问:
我有一个代码盯着一些正在修改我的 React 状态的异步函数。但问题是,在解决所有承诺后启动其他函数时,该函数没有我的状态的更新版本:
const [myState, setMyState] = useState<myType[]>({...});
const pendingPromises: Promise<void>[] = [];
async function asyncFunction(a: myType){
return fs.promises.copyFile(a.currentPath, a.destination).then(() => {
setMyState((myState) => [...myState.filter((b) => (b.id != a.id)), {...a, curentPath: a.destination}]
function saveMyState(){
// Actually just saving it to a JSON
console.log(myState) // This shows the original state before it has been modified by asyncFunction()
}
function mainFunction(){
myArray.forEach((a) => pendingPromises.push(asyncFunction(a))
Promise.all(pendingPromises).then(saveMyState)
}
因此,为了解决这个问题,我声明了一个新状态,当我需要调用第二个函数时,我会将其更改为 true:
const [myState, setMyState] = useState<myType[]>({...});
const [callFunction, setCallFunction] = useState<boolean>(false);
const pendingPromises: Promise<void>[] = [];
useEffect(() => {
if (callFunction) {
saveMyState();
setCallFunction(false);
}
}, [callFunction]);
async function asyncFunction(a: myType){
return fs.promises.copyFile(a.currentPath, a.destination).then(() => {
setMyState((myState) => [...myState.filter((b) => (b.id != a.id)), {...a, curentPath: a.destination}]
});
function saveMyState(){
// Actually just saving it to a JSON file
console.log(myState) // This shows the original state before it has been modified by asyncFunction()
}
function mainFunction(){
myState.forEach((a) => pendingPromises.push(moveFile(a))
Promise.all(pendingPromises).then(() => setCallFunction(true)) // calling function
}
这很有效,但感觉不是很干净。这种方式可以吗?如果没有,我应该如何进行?
答:
通常在这种情况下,所讨论的函数正在更改状态,因此使用状态 setter 的回调形式是简单的解决方案。但不会改变状态,它只是使用它。saveMyState
在这种情况下,最好不要通过设置该状态标志来调用函数来导致重新呈现。
以下是一些替代方案:
由于 的工作是将当前状态保存为 JSON,因此您可以考虑在状态更改时执行此操作,而不是让 JSON 版本在一段时间内与状态保持不同步。要做到这一点,根本不需要调用它,只需在以下位置进行以下工作:
saveMyState
Promise.all(/*...*/).then
useEffect
useEffect(() => { // ...save `myState` as JSON... }, [myState]); // <== Triggers the effect callback when `myState` changes
无论如何,您可以继续使用状态 setter 的回调形式,只需返回它收到的相同状态,使状态更新调用不执行任何操作:
function saveMyState(){ setMyState((state) => { // ...save `state` as JSON... return state; // Return state unchanged }); }
我已经这样做了几次,但从来没有真正满意过。:-)
您可以使用 to always have access to up-to-date state:
ref
const [myState, setMyState] = useState<myType>({/*...*/}); const refMyState = useRef(myState); // Using the initial value here just // makes the types easier refMyState.current = myState; // Make sure the ref is always up-to-date // (You *could* put the update in a // `useEffect`, but that's needlessly // complex.) // ... function saveMyState(){ const state = refMyState.current; // ...save `state` as JSON... }
使用其他机制来存储,而不是 ,例如 Redux。(这样做是一个足够大的变化,我不会做一个例子,他们的文档已经涵盖了它。
myState
useState
信号的好处是,无论你有多少反应子项,只有那些监听信号的人才会重新渲染。包含上述组件的所有内容,无论是上下文还是 useRef,其所有链都将在任何更改时重新呈现。
如果你想创建信号 - 在窗口对象上创建一个观察者,任何 react 组件都可以监听。类似于 javascript 代理的东西。下面是一个示例:
评论
pendingPromises
[<>]
setMyState()
asyncFunction
setMyState()
asyncFunction
mainFunction()
doStuffWithUpdatedState
setMyState()
doStuffWithUpdatedState
saveMyState