我面临这个问题。 当我有一个Axios调用时,它承诺会调度一个操作来更新Redux并执行回调。 但是当执行回调时,redux状态似乎已过时。
i got a sandbox code for demo here
如果单击getNewDate按钮,控制台将显示redux状态的差异。 当redux导致重新渲染时,状态将是正确的。
如何在回调过程中获得正确的redux状态?
答案 0 :(得分:2)
响应始终是陈旧的,这就是React挂钩的工作方式。创建它们时,它们对每个单独渲染中的所有变量应用闭包。如果您绝对需要该值在回调函数(或效果)中不会过时,请为此设置引用。
environment.production ? // "forFeature" because this is a module of a feature
of my app which is loaded lazily
[] : HttpClientInMemoryWebApiModule.forFeature(
AppointmentFakeBackendService, {
apiBase: 'api'/
}
),
设置引用后,您会清楚地看到响应实际上是在变化的,并且responseRef.current与data.newDate显示相同的值。
您必须在这里使用LayoutEffect,因为对于回调而言,效果运行的顺序是错误的。由于useEffect在组件重新渲染后运行,而useLayoutEffect在组件重新渲染时运行。
另一种方式可以看到useSelector可以正常工作并进行更新,并且MyPages.tsx可以看到更新为useEffect,以便在更改时记录更改。
const { response, getNewDate } = useResponse();
const responseRef = useRef(response);
useLayoutEffect(() => {
responseRef.current = response;
}, [response]);
const callbackSuccessful = (data: IResponse) => {
console.log("response is not Stale: " + responseRef.current.newDate);
console.log("should be: " + data.newDate);
};
如果您想在回调中访问最新的redux存储状态而根本没有任何时序问题,则useStore会有所帮助,并且完全不会导致重新呈现。
useEffect(() => {
console.log(response.newDate)
}, [response]);
https://codesandbox.io/s/react-typescript-demo-pek65?file=/src/pages/MyPages.tsx
答案 1 :(得分:0)
使用扎卡里·哈伯useLayoutEffect
的先前答案是正确的答案。
但这是我可以分享的两个低于标准的解决方案,都有各自的问题。
解决方案1
在按钮上使用key
通知React,它应该更新按钮对象的范围(即重新安装组件),因为它的某些依赖项已更新。
import React from "react";
import { useResponse } from "../hooks/useResponse";
import { IResponse } from "../utils/apiDef";
const MyPages = () => {
const { response, getNewDate } = useResponse();
const callbackSuccessful = (data: IResponse) => {
console.log("response is: " + response.newDate)
console.log("callback data is: " + data.newDate)
}
const callbackFail = (data: any) => {
}
const handleButton = () => {
getNewDate(callbackSuccessful, callbackFail)
}
const buttonKey = response.newDate
return <div>
hello world {response.newDate}
<br/>
<button key={buttonKey} type="button" onClick={handleButton}>getNewDate</button>
</div>;
};
export default MyPages;
一个小问题:这将显示先前的结果,即response.newDate
将包含更改key
时的值。
解决方案2
使用全局变量,例如state
import React from "react";
import { useResponse } from "../hooks/useResponse";
import { IResponse } from "../utils/apiDef";
const state = {
response: undefined
}
const MyPages = () => {
const { response, getNewDate } = useResponse();
state.response = response;
const callbackSuccessful = (data: IResponse) => {
console.log("state response is: " + state.response.newDate)
console.log("callback data is: " + data.newDate)
}
const callbackFail = (data: any) => {
}
const handleButton = () => {
getNewDate(callbackSuccessful, callbackFail)
}
return <div>
hello world {response.newDate}
<br/>
<button type="button" onClick={handleButton}>getNewDate</button>
</div>;
};
export default MyPages;
在回叫中,state.response.newDate
等于data.newDate
。
一个小问题:它不再是可重用的组件。仅当您的应用中有一个MyPages
对象时,此解决方案才有效。所有实例都指向相同的static
全局变量,这将引发争夺最后获胜者的争执。
您不应这样做:
<MyPages />
<MyPages />
此解决方案的另一个问题是:React的优化;我不知道这会如何影响它。
我希望这会有所帮助。