【问题标题】:setState causing memory leak inside subject subscribesetState 导致主题订阅内的内存泄漏
【发布时间】:2021-08-26 09:06:23
【问题描述】:

第二次导航到TestPage 时遇到错误。该代码在第一次导航时运行良好,但在第二次导航时出现错误。

Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.

我注意到,如果我删除 setinterval 块,错误不会发生。

来自 observable 的数据在 Text 中反映良好,但我无法理解导致此错误的原因。因此我的问题是为什么 setState 在可观察订阅中不起作用?

export const testSubject = new Subject<any>();
setInterval(() => {
    testSubject.next({ dest: 'any', msg: [] });
}, 2000);

function TestPage({ route, navigation }) {
    const [data, setData] = useState<any[]>([]);

    useFocusEffect(
        useCallback(() => {
            testSubject.subscribe(({ dest, msg }) => {
                setData(msg);
            });
            return () => _cleanup();
        }, []),
    );

    const _cleanup = () => {};

    return (
        <View>
            <Text>{JSON.stringify(data)}</Text>
            <Button
                onPress={() => {
                    navigation.navigate('home');
                }}
                title="back"
            />
        </View>
    );
}

export default TestPage;

【问题讨论】:

  • 组件卸载时是否需要取消订阅testSubject? (还是关闭流?
  • 没有。该主题正在多个组件中使用。我在这里展示的只是一个问题的表示。

标签: reactjs react-native rxjs react-navigation


【解决方案1】:

我不确定useFocusEffect(useCallback(...)) 到底是什么,但我认为它相当于普通的useEffect

您遇到的问题是当组件卸载时您没有清理对流的订阅。当 testSubject 有新更新时,旧实例(已卸载)将在卸载组件上调用 setData(),并且 react 会抱怨。

为什么_cleanup 函数什么都不做?你只需要完成它:

    useFocusEffect(
        useCallback(() => {
            const subscription = testSubject.subscribe(({ dest, msg }) => {
                setData(msg);
            });
            return () => {
                subscription.unsubscribe();
            }
        }, []),
    );

这应该可行。

【讨论】:

  • 我不想取消订阅该主题。该主题是全球性的,并被不同的组件使用。如果我按上述方式取消订阅,其他组件将停止工作。另外,根据你的回答,react 应该在第一次调用后每次都抛出错误,但它只是抛出一次错误,之后它会按预期工作。
  • 注意我没有做testSubject.unsubscribe()。正如你所说,它会关闭主题,没有人可以使用它。我所做的是关闭这个特定组件对 testSubject 的订阅。我建议您尝试一下(取消订阅subscription,而不是testSubject),您将看到这如何解决您的问题而无需实际关闭主题
  • React 仅显示警告一次不是垃圾邮件。这是一个警告,而不是错误,它只是告诉你,你可能在需要关闭它们的地方打开了订阅,但 react 将继续正常工作(但你有内存泄漏)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-06
  • 2014-06-07
  • 2013-11-20
  • 2011-10-28
  • 2016-01-18
相关资源
最近更新 更多