【问题标题】:Why am I getting the following React Native warning: Can't perform a React state update on an unmounted component为什么我收到以下 React Native 警告:Can't perform a React state update on an unmounted component
【发布时间】:2020-06-28 16:12:30
【问题描述】:

我正在尝试构建一个 React Native 应用程序,但对 React/RN 生态系统还是个新手,所以我可能只是误解了我遇到的问题的一些明显问题。

我有一个应用程序,其中很多页面的结构如下:

<View>
    <NavComponent />
    <View>
        {/* Page component structure/logic here */}
    </View>
</View>

NavComponent 加载带有TouchableOpacity 元素的可切换导航菜单,如下所示:

Go to Screen #1
Go to Screen #2
Go to Screen #3

我遇到的问题(也许这不是问题,而是 React/RN 的工作原理)是,如果我从屏幕 #1 开始,打开导航,转到屏幕 #2,打开再次导航,然后返回到屏幕 #1,即使屏幕 #1 再次出现,屏幕 #1 的实际渲染函数似乎也没有被再次调用,因为 NavComponent 是每个屏幕渲染的一部分屏幕,当我再次尝试从屏幕 #1 打开导航时,我收到以下警告:

警告:无法对未安装的组件执行 React 状态更新。 这是一个空操作,但它表明您的应用程序中存在内存泄漏。 要解决此问题,请取消 %s 中的所有订阅和异步任务。%s,a useEffect 清理函数...

再一次,也许我的应用程序一开始就有缺陷,但本质上,当我从导航从一个屏幕转到另一个屏幕时,我总是希望新屏幕从头开始重新渲染(包括最初的 Ajax 调用用于数据)。

这里有一个更充实的屏幕渲染函数示例(它们都遵循相同的基本模式):

const screen1 = ({ navigation }) => {
    const [serverData, setServerData] = useState(null);

    useEffect(() => {
        // getPageData is a custom method I added to axios.
        axios.getPageData('/api/url/here', (data) => {
            setServerData(data);
        });
    }, []);

    if (serverData) {
        const { meta, user, data } = serverData;

        return (
            <View>
                <NavComponent />
                <View style={styles.container}>
                    {/* Page component structure/logic here */}
                </View>
            </View>
        );
    }

    return null;
};

例如,如果我在上面的渲染函数的开头添加了一个console.log,它会在屏幕第一次加载时调用,但是如果我转到屏幕#2,然后通过以下方式返回到屏幕#1导航组件,console.log 不再输出。为什么?

为了它的价值,我使用NavComponent 中的标准navigation.navigate('ScreenName') 在屏幕之间切换。

任何有关如何修复警告(和/或更好地设计应用程序)的建议,以便我可以在每个页面上都有该导航,我们将不胜感激。谢谢。

【问题讨论】:

    标签: javascript reactjs react-native react-hooks use-state


    【解决方案1】:

    您的 api 调用导致警告,在 react/native 生态系统中,当从树中删除组件时,开发人员需要取消所有订阅(事件侦听器)和异步任务(从网络获取数据) ,这些功能需要由开发者取消,因为 react/native 无法为您执行此操作。

    要在基于类的组件中处理该问题,您需要执行 componentWillUnmount 并删除那里的订阅

    class MyClass extends Component {
       componentWillUnmount() {
         // remove listeners and cancel requests
        }
    
    

    但在现代钩子组件中,您需要返回一个 cleanup 函数,该函数将在 useEffect 中返回,react 将调用该函数以取消您所做的任何订阅,在您的情况下,只需return a cleanup function 应该为您删除该警告

    
      const [mounted, setIsMounted] useState(false)
     useEffect(() => {
            // getPageData is a custom method I added to axios.
            setIsMounted(true)
            axios.getPageData('/api/url/here', (data) => {
                if(isMounted)
                 setServerData(data);
            });
    
            return () => {
                 setIsMounted(false)
             }
        }, []);
    
    

    【讨论】:

    • 艾哈迈德,感谢您的解释。我完全没有意识到这一点。不幸的是,我添加了空回调函数返回到useEffect,但我仍然得到与以前相同的错误,并且我仍然没有看到我添加到屏幕#1 顶部的console.log 以确保它是重新- 每次渲染。另外,即使我最初没有它,我在NavComponent 中添加了一个useEffect 钩子并返回了一个空函数,但我仍然遇到同样的错误。有什么想法吗?
    • screen#2 @HartleySan 怎么样
    • 是的,我都做了。没有变化。
    • 这篇文章可能对你有帮助juliangaramendy.dev/use-promise-subscription
    • 艾哈迈德,这很有趣,但经过进一步调查,我看到了一些事情:1)警告仅出现在屏幕#1,这是登录应用程序后自动加载的屏幕. 2) 如果我将登录后加载的屏幕从屏幕#1 更改为屏幕#2,则警告仅出现在屏幕#2。 3) 警告似乎与我每次导航到它们时所有其他屏幕都正确重新加载的事实有关,除了登录时加载的初始屏幕。我什至不需要返回 () =&gt; {}; 来强制它发生。有什么想法吗?
    猜你喜欢
    • 2019-10-29
    • 2020-01-15
    • 2021-03-25
    • 2020-05-15
    • 2021-05-05
    • 2022-01-11
    • 2022-06-10
    • 2022-06-10
    • 2020-09-10
    相关资源
    最近更新 更多