Не удается выполнить обновление состояния реакции для размонтированного компонента 2021

#reactjs #react-native #use-effect

Вопрос:

Предупреждение: Не удается выполнить обновление состояния реакции для размонтированного компонента. Это не операция, но это указывает на утечку памяти в вашем приложении. Чтобы исправить это, отмените все подписки и асинхронные задачи в функции очистки 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
 

Редактировать, Код Входа в систему:
Ниже приведен полный код файла, в котором обнаружена ошибка.

Возвращаемая ошибка: Предупреждение: Не удается выполнить обновление состояния реакции для размонтированного компонента. Это не операция, но это указывает на утечку памяти в вашем приложении. Чтобы исправить это, отмените все подписки и асинхронные задачи в функции очистки useEffect.

А также: Ошибка: Отрисовано больше крючков, чем во время предыдущего рендеринга.

Эта ошибка находится по адресу: в Perfil (в SceneView.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
    }
    });
 

Ответ №1:

Вы useEffect потенциально можете попытаться обновить состояние вашего компонента, когда он будет размонтирован. Вот почему вы получаете предупреждение.

Например, getData вызывается useEffect , и и, пока он ждет, компонент может быть размонтирован. Поэтому, если ваш асинхронный 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 . Что мы можем гарантировать, будет установлено значение false при отключении компонента, включив функцию очистки в качестве возврата useEffect .

Комментарии:

1. К сожалению, сообщение об ошибке не помогает, так как у нас нет контекста того, что Perfil (at SceneView.tsx) есть. Попробуйте, по крайней мере, обновить свою страницу. Вы получаете Rendered more hooks than previous render ошибку.

2. Здравствуйте, я изменил сообщение и добавил файл, который использует эту функцию, не могли бы вы проанализировать его, пожалуйста?