【问题标题】:Can't update react state, even component is not unmounted无法更新反应状态,即使组件没有卸载
【发布时间】:2020-12-14 10:24:50
【问题描述】:

说明

我有一个组件,它显示从服务器获取的数据,并使用状态、tableData 将其显示在表格上,并且 它必须在调度 Redux 操作时设置

我使用了动作监听器库,它使用了Redux middleware,它由 63 行代码组成。 redux-listeners-qkreltms.

例如,当我在analysisListIsReady({}).type 上注册一个函数,即ANALYSISLIST_IS_READY 时,当动作被调度时,该函数被调用。

问题

问题是反应有时会抛出错误:Can't update react state... for setTableData 因此忽略设置响应数据。我想弄清楚它什么时候发生。

我假设是因为卸载组件,所以我打印了一些日志,但是没有打印任何日志,并且 ComponentA 也没有消失。

删除getAnalysisJsonPathApigetResource 时没有出现任何错误,所以我尝试重新处理它,但失败了...link

当我删除 listenMiddleware.addListener 时不会出现任何错误,请参阅:#2

#1

// ComponentA
const [tableData, setTableData] = useState([])
useEffect(() => {
  return () => {
    console.log("unmounted1")
}}, [])  

useEffect(() => {
    listenMiddleware.addListener(analysisListIsReady({}).type, (_) => {
      try {
        getAnalysisJsonPathApi().then((res) => {
          //...
          getResource(volumeUrl)
            .then((data: any) => {
              // ...
              setTableData(data)
            })
        })
      } catch (error) {
        warn(error.message)
      }
    })

    return () => {
      console.log("unmounted2")
    }
  }, [])
export const getAnalysisJsonPathApi = () => {
  return api
    .post('/segment/volume')
    .then(({ data }) => data)

export const getResource = async (src: string, isImage?: boolean): Promise<ArrayBuffer> =>
  api
    .get(src)
    .then(({ data }) => data)

#2

// ComponentA
const [tableData, setTableData] = useState([])
useEffect(() => {
  return () => {
    console.log("unmounted1")
}}, [])  

useEffect(() => {
    if (steps.step2a) {
      try {
        getAnalysisJsonPathApi().then((res) => {
          //...
          getResource(volumeUrl)
            .then((data: any) => {
              // ...
              setTableData(data)
            })
        })
      } catch (error) {
        warn(error.message)
      }
    }

    return () => {
      console.log("unmounted2")
    }
  }, [steps.step2a])

【问题讨论】:

    标签: reactjs redux middleware


    【解决方案1】:

    嗯,正如你所说:

    因为组件卸载

    在你的UseEffect()函数中,你需要检查组件是否挂载,换句话说,你需要做componentDidMount & componentDidUpdate(如果需要)的逻辑:

    const mounted = useRef();
    
    useEffect(() => {
    if (!mounted.current) {
        // do componentDidMount logic
        console.log('componentDidMount');
        mounted.current = true;
    } else {
        // do componentDidUpdate logic
        console.log('componentDidUpdate');
    }
    });
    

    【讨论】:

      【解决方案2】:

      我没有查看您的问题代码详细信息,但我的提示可能会对您有所帮助,通常此错误发生在 fetchData 函数中, 假设你有一个如下所示的 fetchData 函数:

      fetchData(){
      ...
      let call = await service.getData();
      ...
      --->setState(newItems)//Here
      }
      

      所以当 api 调用结束并要更新状态时,如果组件已卸载,则没有要设置的状态, 您可以使用 bool 变量并在组件卸载时将其设置为 false:

          let stillActive= true;
          
          fetchData(){
          active = true;
          ...
          let call = await service.getData();
          ...
          if(stillActive)
             setState(newItems)//Here
          }
          }
      
          componentWillUnmount(){
              active = false;
          }
      

      【讨论】:

        【解决方案3】:

        我发现这是因为 redux-listeners-qkreltms,Redux 中间件。

        当组件被挂载到监听器时,它保持功能,但即使组件被卸载,它也不会改变它的功能。

          middleware.addListener = (type, listener) => {
            for (let i = 0; i < listeners.length; i += 1) {
              if (listeners[i].type === type) {
                return;
              }
            }
            listeners.push(createListener(type, listener));
          };
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2023-03-19
          • 2020-11-26
          • 2022-11-22
          • 2021-12-02
          • 1970-01-01
          • 2020-07-22
          • 1970-01-01
          相关资源
          最近更新 更多