如何清理 useEffect 中的 Redux“useDispatch”操作?
Posted
技术标签:
【中文标题】如何清理 useEffect 中的 Redux“useDispatch”操作?【英文标题】:How to clean up a Redux "useDispatch" action inside useEffect? 【发布时间】:2021-01-04 17:51:34 【问题描述】:我找到了很多这方面的例子,但没有一个使用 Redux 和useDispatch
,所以情况是这样的......
我有一个带有像这样的异步操作的操作文件...
//postsActions.tsx
export const asyncGetPostById = (postId: string) =>
return async (dispatch: any, getState: () => AppState) =>
try
dispatch(startLoader());
const data = await axios.get(`api/posts/$postId`);
dispatch(setPostDataInReducer(data));
catch (error)
console.log(error)
;
;
我在 Post.tsx
组件中调用这个动作,就像这样......
const dispatch = useDispatch();
useEffect(() =>
dispatch(asyncGetPostById(postId));
, []);
这当然是一个简化的版本,但它的想法是一样的。现在我怎样才能清理像useEffect
这样的调度以避免这个错误......
警告:无法对未安装的组件执行 React 状态更新。 这是一个空操作,但它表明您的应用程序中存在内存泄漏。 要修复,请取消 useEffect 中的所有订阅和异步任务 清理功能。
编辑
这个想法是如何取消 ComponentWillUnmount 上的请求(或者在我的情况下是 useEffect
中的清理功能),如果它还没有完成,这样你就不会在后台有过时或未解决的请求,这将使你的应用程序慢。
这是一个非常常见的问题,很多人都成为受害者,并且有很多解决方案,但不适用于这种特殊情况(使用 dispatch 和 redux)。
有些使用AbortController()
,有些使用axios.CancelToken
,但我不知道在我的情况下如何使用它们。
【问题讨论】:
axios.get
解决时组件可能已卸载的问题?我能想到一个丑陋的解决方案(传入一个在卸载时发生突变的对象),希望有更好的解决方案
是的,这就是问题所在,有些使用axios.CancelToken
,有些使用AbortController
,但我不知道在这种情况下如何在dispatch和redux中使用这些。
这个想法是如何取消 ComponentWillUnmount 上的请求,如果它还没有完成,这样您就不会在后台有陈旧或未解决的请求,这会使您的应用程序变慢。
这不应该引发错误,除非您在请求完成后设置要声明的内容。但是,如果您想取消请求,那么您将使用您提到的选项之一(尽管AbortController 在某些浏览器中不起作用)。另一种方法是使用 redux sagas 而不是 thunk,它允许您手动取消任务。也就是说,如果没有 repo 或工作演示,就很难推荐最佳方法。
@MattCarlotta 我确实在请求之后更改了状态,或者更确切地说是减速器,在某些情况下,我调度了另一个异步操作,它也更新了减速器。我只需要知道如何取消上述示例中的请求即可。
【参考方案1】:
为你的动作创建者试试这个:
export const asyncGetPostById = (postId: string) => async (dispatch: Function, getState: () => AppState) =>
try
dispatch(startLoader());
const data = await axios.get(`api/posts/$postId`);
dispatch(setPostDataInReducer(data));
catch (error)
console.log(error)
;
这是一个微妙的变化,但是使用这个动作创建器,你实际上并没有返回任何东西(在 TypeScript 中它应该是 void
)
使用void
返回,您在动作创建器中的dispatch
调用将直接转到您的reducer,但在您的组件中不会返回任何内容,因此您不必清理任何内容。
编辑:
此外,您应该考虑将dispatch
添加到您的useEffects
依赖数组中:
const dispatch = useDispatch();
useEffect(() =>
dispatch(asyncGetPostById(postId));
, [dispatch]);
【讨论】:
好吧,我发现我遇到的问题是因为我在调度完成之前关闭了弹出窗口,所以我所要做的就是在弹出窗口中创建 async-await 函数并等待调度然后关闭弹出窗口,它工作。但是,我仍然想知道如何清理 useEffect 中的调度。 很高兴您解决了这个问题。据我所知,您不需要清理 redux 调度;您没有使用它进行任何订阅,因此您不必清理任何东西。【参考方案2】:你必须在你的 reducer 中创建一个 case
来清理当前状态。然后在useEffect
中你会这样做
React.useEffect(()=>
dispatch(your_action)
return () => dispatch(clean_data_action)
,[])
【讨论】:
不是这样,不是。 根据本次讨论:github.com/facebook/react/issues/14285,您似乎无法从 useEffect 清理函数中调度操作 我在一个项目中做了这个。您可以在清理功能上调度操作 你能解释一下@Ruby 为什么不是这样吗?我也有类似的问题以上是关于如何清理 useEffect 中的 Redux“useDispatch”操作?的主要内容,如果未能解决你的问题,请参考以下文章
如何取消 useEffect 清理函数中的所有订阅和异步任务?
useEffect TypeScript 错误中的 Redux 操作?
如何在页面加载时调度 redux 操作以在 useEffect 中加载数据
使用 Redux Thunk 时正确理解 useEffect 中的依赖数组