【问题标题】:How to clean up redux state with redux thunk when unmounting component before finishing fetch in useEffect?在 useEffect 中完成获取之前卸载组件时如何使用 redux thunk 清理 redux 状态?
【发布时间】:2021-04-27 08:38:54
【问题描述】:

在使用 react-redux 和 redux thunk 一段时间后,我意识到了一种行为,这并不是最好的用户体验。

我知道,当您使用 react 并在组件渲染时在 useEffect 中获取数据时,并且出于任何原因您返回或导航到其他地方时,您需要使用返回中的函数清除状态(这将重新创建 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())
},[ ])

如您所见,当组件卸载 BUUUUT 时,我正在调度一个 resetData 操作来清除状态,这就是问题所在。如果在获取数据之前用户导航到另一个页面,resetData 将被调度,但由于获取无法完成,数据将在重置后存储。因此,当用户导航回该组件时,它会在加载新数据之前闪烁(仅非常快速地显示,可能会显示一秒钟)旧数据。那么有什么办法可以避免 redux thunk 出现这个问题呢?

PD:我可以用背景挡住导航或整个屏幕,这样用户在获取完成之前不会导航,但我觉得这是一种解决问题的方法。但是,如果您认为这仍然是最好的方法,请告诉我。

谢谢。

【问题讨论】:

    标签: reactjs react-redux redux-thunk


    【解决方案1】:

    您可以创建一个 AbortController 实例。该实例具有信号属性,我们将信号作为获取选项传递。然后为了取消数据获取,我们调用 AbortController 的 abort 属性来取消所有使用该信号的获取。

    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
    },[ ])
    

    【讨论】:

    • 感谢您的回答。我还有几个问题,应该在减速器中调用 controller.abort 吗?如果组件以正常方式卸载怎么办?该控制器中止会产生任何影响吗?.. 例如,如果我在 useEffect 中有超过 1 次获取,我应该在每次重置时调用 controller.abort 吗?
    • 您可以调用它,然后将所有控制器保存在某个对象中,如下所示:链接].abort()
    • 好的,我会按照你说的去做。目前我尝试过并且正在工作。在我的示例中,我只是在调度 fetchStart 操作时存储控制器,并且在减速器中我编写了这种情况 RESET_DATA: if(state.controller) state.controller.abort() return initialState
    猜你喜欢
    • 2021-08-05
    • 1970-01-01
    • 2018-11-14
    • 2021-06-16
    • 2020-01-29
    • 2020-03-04
    • 1970-01-01
    • 2018-08-02
    • 1970-01-01
    相关资源
    最近更新 更多