如何使用React钩子和Redux从useEffect执行store.unsubscribe

时间:2019-11-25 15:16:40

标签: javascript reactjs redux react-hooks

我有一个使用redux和hook的React无状态组件。我需要显示页面加载时的项目数(useEffect),并在每次添加或删除项目(store.subscribe)时进行更新

useEffect(() => {
    setState({
        items: store.getState().items.length
    });
}, []);

store.subscribe(() => {
    setState({
        items: store.getState().items.length
    });
});

但是这导致控制台显示警告无法在已卸载的组件上执行React状态更新。这是空操作,但它表明应用程序中发生内存泄漏。要修复,请取消使用useEffect清理功能中的所有订阅和异步任务。

如何从useEffect内部退订?

3 个答案:

答案 0 :(得分:1)

从useEffect返回一个函数进行清理。因此,在卸载组件时将调用返回的函数。

store.subscribe返回一个取消订阅的函数。使用useRef钩子保存其引用,并从useEffect钩子返回相同的引用。

在文档https://reactjs.org/docs/hooks-effect.html#effects-with-cleanup中对其进行阅读。

const storeRef = useRef(() => {});
useEffect(() => {
  storeRef.current = store.subscribe(() => {
    setState({
      items: store.getState().items.length
    });
  });

  return storeRef.current;
}, []);

useEffect(() => {
  setState({
    items: store.getState().items.length
  });

  return storeRef.current;
}, []);

答案 1 :(得分:0)

如果将useEffect调用的第二个参数设置为[],则效果回调函数将充当ComponentDidMount。如果该回调函数返回一个函数,则该函数将在卸载组件(ComponentWillUnmount)之前被调用。

我猜这个setState应该用setItems替换,如下所示。 请尝试此代码。

const [items, setItems] = useState([]);
useEffect(() => {
    setItems(store.getState().items.length);
    
    
    const unsubscribe = store.subscribe(() => {
        setItems(store.getState().items.length);
    });
    
    return unsubscribe;
}, []);

答案 2 :(得分:0)

一开始不应该直接使用商店。

如果您需要从存储中读取值作为组件的一部分,则应使用对您有用的React-Redux API:connectuseSelector。他们已经根据需要管理订阅和取消订阅商店的工作,因此您的组件可以仅指定它需要的数据。