在 useEffect 中完成提取之前卸载组件时如何使用 redux thunk 清理 redux 状态?
How to clean up redux state with redux thunk when unmounting component before finishing fetch in useEffect?
在使用 react-redux 和 redux thunk 一段时间后,我意识到一种行为,这不是最好的用户体验。
我知道,当您使用 React 并在渲染组件时在 useEffect 中获取数据,并且出于任何原因返回或导航到其他地方,您需要使用 [= 中的函数清除状态26=](这将重新创建 componentWillUnmount 生命周期)
我遇到的这个问题是在使用 redux thunk 时发生的,因为数据获取是与动作创建者一起进行的。因此,长话短说,我将展示一些代码。获取操作看起来像这样:
export const fetchData = () => async (dispatch, getState) => {
try {
dispatch(fetchDataStart())
const response = await fetch('https://jsonplaceholder.typicode.com/photos')
dispatch(fetchDataSucess(data))
} catch (error) {
console.log(error)
}
}
假设我在我的组件 useEffect 中这样调用此操作:
useEffect(() => {
const loadData = async () => {
await dispatch(fetchData())
}
loadData()
return () => dispatch(resetData())
},[ ])
如您所见,我正在分派一个 resetData 操作以在组件卸载时清除状态 BUUUUT 这就是问题所在。如果在获取数据之前用户导航到另一个页面,将调度 resetData 但由于获取无法完成,数据将在重置后存储。因此,当用户导航回该组件时,它会在加载新数据之前闪烁(仅快速显示,可能一秒钟)旧数据。那么redux thunk有没有办法避免这个问题呢?
PD:我可以用背景挡住导航或整个屏幕,这样用户在获取完成之前不会导航,但我觉得这是解决问题的一种方法。但是,如果您认为这仍然是最好的方法,请告诉我。
谢谢。
您可以创建一个 AbortController 实例。该实例有一个信号 属性,我们将该信号作为获取选项传递。然后为了取消数据获取,我们调用 AbortController 的中止 属性 来取消所有使用该信号的获取。
export const fetchData = () => async (dispatch) => {
try {
const controller = new AbortController();
const { signal } = controller;
dispatch(fetchDataStart(controller)); // save it to state to call it later
const response = await fetch('https://jsonplaceholder.typicode.com/photos', { signal });
dispatch(fetchDataSucess(data));
} catch (error) {
console.log(error);
}
}
使用效果:
useEffect(() => {
dispatch(fetchData());
return () => dispatch(resetData()) // resetData will call controller.abort() that was saved in state
},[ ])
在使用 react-redux 和 redux thunk 一段时间后,我意识到一种行为,这不是最好的用户体验。
我知道,当您使用 React 并在渲染组件时在 useEffect 中获取数据,并且出于任何原因返回或导航到其他地方,您需要使用 [= 中的函数清除状态26=](这将重新创建 componentWillUnmount 生命周期)
我遇到的这个问题是在使用 redux thunk 时发生的,因为数据获取是与动作创建者一起进行的。因此,长话短说,我将展示一些代码。获取操作看起来像这样:
export const fetchData = () => async (dispatch, getState) => {
try {
dispatch(fetchDataStart())
const response = await fetch('https://jsonplaceholder.typicode.com/photos')
dispatch(fetchDataSucess(data))
} catch (error) {
console.log(error)
}
}
假设我在我的组件 useEffect 中这样调用此操作:
useEffect(() => {
const loadData = async () => {
await dispatch(fetchData())
}
loadData()
return () => dispatch(resetData())
},[ ])
如您所见,我正在分派一个 resetData 操作以在组件卸载时清除状态 BUUUUT 这就是问题所在。如果在获取数据之前用户导航到另一个页面,将调度 resetData 但由于获取无法完成,数据将在重置后存储。因此,当用户导航回该组件时,它会在加载新数据之前闪烁(仅快速显示,可能一秒钟)旧数据。那么redux thunk有没有办法避免这个问题呢?
PD:我可以用背景挡住导航或整个屏幕,这样用户在获取完成之前不会导航,但我觉得这是解决问题的一种方法。但是,如果您认为这仍然是最好的方法,请告诉我。
谢谢。
您可以创建一个 AbortController 实例。该实例有一个信号 属性,我们将该信号作为获取选项传递。然后为了取消数据获取,我们调用 AbortController 的中止 属性 来取消所有使用该信号的获取。
export const fetchData = () => async (dispatch) => {
try {
const controller = new AbortController();
const { signal } = controller;
dispatch(fetchDataStart(controller)); // save it to state to call it later
const response = await fetch('https://jsonplaceholder.typicode.com/photos', { signal });
dispatch(fetchDataSucess(data));
} catch (error) {
console.log(error);
}
}
使用效果:
useEffect(() => {
dispatch(fetchData());
return () => dispatch(resetData()) // resetData will call controller.abort() that was saved in state
},[ ])