reactjs 无法对已卸载的组件执行React状态更新2021

ztyzrc3y  于 2022-12-29  发布在  React
关注(0)|答案(2)|浏览(200)

警告:无法对已卸载的组件执行React状态更新。这是一个无操作,但它指示应用程序中存在内存泄漏。若要修复,请取消useEffect清理函数中的所有订阅和异步任务。

const getData = async () => {
    const jsonValue = await AsyncStorage.getItem("@user-info");
    if(jsonValue != null) {
      setUser(JSON.parse(jsonValue))
    } else {
     setUser(null) 
    }
  };

  useEffect(() => {
    getData();
  }, []);
```[enter image description here][1][enter image description here][2]

  [1]: https://i.stack.imgur.com/y2aSC.png
  [2]: https://i.stack.imgur.com/I3zMY.png

编辑,代码登录:下面是发现错误的文件的完整代码。
错误返回为:警告:无法对已卸载的组件执行React状态更新。这是一个无操作,但它指示应用程序中存在内存泄漏。若要修复,请取消useEffect清理函数中的所有订阅和异步任务。
以及:错误:渲染了比上一次渲染更多的挂接。
此错误位于:在性能文件中(在场景视图中.tsx:122)

import React, { useEffect, useState } from "react";
    import {
      View,
      Image,
      Text,
      TouchableOpacity,
      StyleSheet,
      SafeAreaView,
      Platform,
    } from "react-native";
    import { icons, images } from "../constants";
    import { useFonts } from "expo-font";
    import { theme } from "../styles/theme";
    import AsyncStorage from "@react-native-async-storage/async- 
    storage";

    export const Perfil = () => {
      const [user, setUser] = useState<any>();

      const [loaded] = useFonts({
        Inter: require("../../assets/fonts/Inter-Bold.ttf"),
        InterRegular: require("../../assets/fonts/Inter-Regular.ttf"),
      });

      if (!loaded) {
        return null;
      }

     useEffect(() => {
      let mounted = true;
      const getData = async () => {
        const jsonValue = await AsyncStorage.getItem("@user-info");
        if (mounted === true) {
          if(jsonValue != null) {
            setUser(JSON.parse(jsonValue))
           } else {
            setUser(null) 
         }
       }
     };
    
    getData();
    return () => {
      mounted = false;
    } 
    }, []);

    function renderHeaderSection() {
    return (
      <View style={styles.header}>
        {/* Image */}
        <Image source={images.UserProfileImg} style={styles.userImg} />

        {/* User Name */}
        <Text style={styles.userName}>{user?.user?.givenName} {user?.user?.familyName}</Text>

        {/* Email */}
        <Text style={styles.userEmail}>{user?.user?.email}</Text>

        {/* Button Edit Profile */}
        <TouchableOpacity style={styles.buttonProfile}>
          <Text style={styles.textButtonProfile}>Editar Perfil</Text>
          <Image
            source={icons.ArrowRightImg}
            style={{ tintColor: theme.colors.white, width: 8, height: 14 }}
          />
        </TouchableOpacity>
      </View>
    );
    }

    function renderPreferencesSection() {
    return (
      <View>
        {/* Preferences */}
        <View style={styles.preferences}>
          <Text style={styles.textPrefences}>Preferences</Text>
        </View>
      </View>
    )
    }

    return (
      <SafeAreaView style={styles.container}>
        {renderHeaderSection()}
        {renderPreferencesSection()}
      </SafeAreaView>
    );
    };

    const styles = StyleSheet.create({
     container: {
      flex: 1,
      backgroundColor: theme.colors.white,
      paddingTop: Platform.OS === "android" ? 50 : 0,
      alignItems: 'center'
     },
     header: {
      alignItems: "center",
      justifyContent: "center",
     },
     userImg: {
      width: 70,
      height: 70,
      borderRadius: 100,
     },
    userName: {
      fontSize: 18,
      color: theme.colors.black,
      paddingVertical: 6,
      fontFamily: "Inter",
    },
    userEmail: {
      fontSize: 14,
      color: theme.colors.black,
      fontFamily: "InterRegular",
    },
    buttonProfile: {
      marginTop: 20,
      height: 40,
      backgroundColor: theme.colors.primary,
      alignItems: "center",
      justifyContent: "center",
      borderRadius: 20,
      paddingHorizontal: 20,
      flexDirection: "row",
    },
    textButtonProfile: {
      color: theme.colors.white,
      fontFamily: "InterRegular",
      fontSize: 14,
      paddingRight: 14,
    },
    preferences: {
      minWidth: '90%',
      height: 40,
      backgroundColor: '#F6F6F6',
      borderRadius: theme.border.radius,
      marginTop: 30,
      justifyContent: 'center',
      paddingLeft: 20
    },
    textPrefences: {
      fontSize: 14,
      color: theme.colors.gray4
    }
    });
qyswt5oh

qyswt5oh1#

useEffect可能会在卸载组件时尝试更新组件的状态,这就是为什么您会收到警告。
例如,getDatauseEffect调用,在它等待的时候,组件可能会被卸载,所以如果你的异步AsyncStorage.getItem调用在组件被卸载后解决,它会尝试在一个不再被装载的组件上调用setUser
如果setUser已挂载,您只能调用它:

useEffect(() => {
    let mounted = true;
    const getData = async () => {
      const jsonValue = await AsyncStorage.getItem("@user-info");
      if (mounted === true) {
        if(jsonValue != null) {
          setUser(JSON.parse(jsonValue))
        } else {
         setUser(null) 
        }
      }
    };
    
    getData();
    return () => {
      mounted = false;
    } 
  }, []);

在这个模式中,本地变量mounted保护setUser不被调用,如果它是false,我们可以通过包含一个cleanup函数作为useEffect的返回值来确保在组件卸载时将其设置为false。

hfwmuf9z

hfwmuf9z2#

这里的问题可能与useFonts有关;
如果你看一下the code,你会发现它在一个异步调用之后调用了一个状态修饰符:

useEffect(() => {
        loadAsync(map).then(() => setLoaded(true))
    }, []); // eslint-disable-line

这足以导致所讨论的错误。
你能做的最好的事情就是忽略这个警告,编写你自己版本的钩子,或者使用像patch-package这样的模块来修补它的行为。

相关问题