我在一个组件中有一个save函数,该函数对API进行一些调用并根据响应更改我的本地状态。然后,我想调度一次操作,并且仅一次完成对setState的调用,例如
const [myData, setMyData] = useState([{id: 0, name: "Alex"}]);
const save = async () => {
if (someCondition) {
let response = await axios.get("/someroute");
if (response.status === 200) {
setMyData([...myData, response.data])])
}
}
if (someOtherCondition) {
let response2 = await axios.get("/someotherroute");
if (response2.status === 200) {
setMyData([...myData, response2.data])])
}
}
dispatch(myAction(myData));
}
现在我知道useEffect应该是解决此问题的方法。例如
useEffect(() => {
dispatch(myAction(myData));
}, [myData]);
但是我要在组件中的其他位置更改myData
,并且我只想在调用save()
并且完成setMyData
后才调度操作。我想不出要检查useEffect()
的条件,除了可能在myData
中添加某种标志,就像一个对象说“准备保存”,但感觉应该更简单一些。方式。
非常感谢您对此提供的任何帮助!
答案 0 :(得分:1)
在其他地方更改myData是什么意思?您是否正在通过从某处获取myData来更改它?因为如果不这样做,setMyData将会非常简单快速地完成其工作。因此,您的保存功能无需监听。
如果由于其他某些获取和保存功能而更改了myData,则应等待它。然后故事会有点复杂。您可能想检查中间件和redux sagas。
我很难理解您的情况和用例;但是,如果在连续的提取操作期间您担心状态覆盖,那么传奇中间件可以解决这个问题。
例如,您可以使用takeLatest创建一些传奇的中间件,以便它将采取已调度的最后一个操作并杀死正在进行的上一个(不等待)操作;因此您可以避免由于副作用而导致的数据覆盖。或者类似地,您可能想要使用takeEvery,它将对设置myData的每个操作进行排队,并且它们将彼此等待结束。
检查更多:https://redux-saga.js.org/
和用法示例:https://codesandbox.io/s/385lk3x6v1?file=/src/sagas/index.js
答案 1 :(得分:0)
似乎您需要使用useReduce
来代替,然后您就可以检测到useEffect
中任何道具何时发生了变化:
const initialState = {
id: null,
name: null,
...
}
const [state, dispatch] = useReducer((state, action) => {
switch (action.type) {
case 'CHANGE-NAME':
return { ...state, name: action.value }
default:
throw new Error('Type not defined')
}
}, initialState)
useEffect(() => {
// Notify changes!!
}, [state.name]);
...
const myFun = async () {
// do something
dispatch({ type: 'CHANGE-NAME', value: 'Hello world' })
}
此外,您还可以将其他道具添加到初始状态,例如,如果您需要特定的标志来一次检测动作,则:)
致谢