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

# #reactjs #firebase #react-native #expo #use-effect

Вопрос:

Я новичок в react native и следовал учебнику на носителе о том, как подключиться к firebase auth. Кажется, все работает нормально, но я продолжаю получать это предупреждение ниже:

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

Я в значительной степени сделал именно то, что было сказано в учебнике, и попробовал еще несколько вещей, чтобы исправить это, но, похоже, ничего не работает. Вот код, на который указывает ошибка:

     let currentUserUID = firebase.auth().currentUser.uid;

    const [firstName, setFirstName] = useState('');

    useEffect(() => { 
        getUserInfo();
      })

      async function getUserInfo(){
        try {
          let doc = await firebase
            .firestore()
            .collection('users')
            .doc(currentUserUID)
            .get();
  
          if (!doc.exists){
            Alert.alert('No user data found!')
          } else {
            let dataObj = doc.data();
            setFirstName(dataObj.firstName)
          }
        } catch (err){
        Alert.alert('There is an error.', err.message)
        }
      }

 

Было бы здорово, если бы кто-нибудь мог помочь мне решить эту проблему и объяснить, что именно пошло не так.

Это ссылка на учебник, которому я следовал:

Ответ №1:

Проблема здесь в том, что вы потенциально ставите в очередь обновление состояния после отключения компонента. Поскольку вы обращаетесь к своему firestore напрямую, асинхронно, вы можете использовать ссылку React для отслеживания того, установлен ли компонент, прежде чем ставить обновление в очередь.

 const isMountedRef = React.ref(null);

useEffect(() => {
  isMountedRef.current = true;               // set true when mounted
  return () => isMountedRef.current = false; // clear when unmounted
}, []);

useEffect(() => {
  async function getUserInfo(){
    try {
      let doc = await firebase
        .firestore()
        .collection('users')
        .doc(currentUserUID)
        .get();

      if (!doc.exists){
        Alert.alert('No user data found!')
      } else {
        let dataObj = doc.data();
        if (isMountedRef.current) { // <-- check if still mounted
          setFirstName(dataObj.firstName);
        }
      }
    } catch (err){
      Alert.alert('There is an error.', err.message)
    }
  }
  getUserInfo();
}, []); // <-- include dependency array, empty to run once when mounting
 

Ответ №2:

Ваша getInfoUser() функция такова async . Вы должны сделать что-то подобное в useEffect :

 useEffect(async () => { await getUserInfo(); }, [])
 

В качестве второго аргумента useEffect используется массив зависимостей. Использование массива зависимостей эквивалентно componentDidMount .

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

 return () => { 
   //do something or cancel a subscription
}
 

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

1. useEffect ответные вызовы hook не могут быть async , поэтому getUserInfo объявляются отдельно и вызываются в ответном вызове hook. Это не очень хороший ответ, так как вы в основном сказали сделать то же самое, что уже указано в предупреждении React.