0

我正在尝试构建一个 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,一个 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不是'不再输出。为什么?

对于它的价值,我正在使用标准navigation.navigate('ScreenName')NavComponent一个屏幕转到另一个屏幕。

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

4

1 回答 1

1

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

要在基于类的组件中处理它,您需要在那里执行componentWillUnmount和删除订阅

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

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


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

于 2020-03-17T15:00:48.663 回答