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

avatar
Gustavo Castilho
8 августа 2021 в 20:05
416
1
-2

Предупреждение. Невозможно выполнить обновление состояния 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.

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

Эта ошибка расположена по адресу: в 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)

avatar
Chan Youn
8 августа 2021 в 20:29
0

Ваш 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.

.
Chan Youn
8 августа 2021 в 22:49
0

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

Gustavo Castilho
8 августа 2021 в 23:24
0

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