Не удается выполнить состояние реакции в React

#reactjs #react-hooks #use-effect

Вопрос:

У меня проблема. просматривал здесь некоторые вопросы, но, похоже, это не работает для меня.

Я получаю эту ошибку на своих трех страницах, когда использую эффект использования.

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

Это код моего эффекта использования

 const UserDetailsPage = () => {


  const classes = useStyles()

  const [userData, setUserData] = useState({
    _id: "",
    name: "",
    phone: "",
    address: "",
    birthdate: "",
    gender: "",
    messenger: "",
    photo: "",
    email: "",
  })
  const [open, setOpen] = useState(false)
  const [loaded, setLoaded] = useState(false)
  const { height, width } = useWindowDimensions()

  const {
    _id,
    name,
    phone,
    address,
    photo,
    gender,
    messenger,
    birthdate,
    email,
  } = userData

  useEffect(() => {
    const user = getUser()

    getUserById("/user/"   user.userId, user.token)
      .then((data) => {
        setUserData(data)
        setLoaded(true)
      })
      .catch((error) => {
        console.log(error)
      })
  }, [])
 

Ответ №1:

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

 const isMountedRef = React.useRef(false);

useEffect(() => {
  isMountedRef.current = true;
  return () => isMountedRef.current = false;
}, []);

useEffect(() => {
  const user = getUser();

  getUserById("/user/"   user.userId, user.token)
    .then((data) => {
      if (isMountedRef.current) {
        setUserData(data);
        setLoaded(true);
      }
    })
    .catch((error) => {
      console.log(error);
    });
}, []);
 

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

1. Я предпочитаю это решение своему, так как isMountedRef его можно повторно использовать в компоненте, если внутри него несколько вызовов API useEffects .

2. @Moistbobo Это также не зависит от жизненного цикла «componentDidUpdate» других useEffect подключений с зависимостями.

Ответ №2:

Это связано с асинхронным вызовом в useEffect завершении, а затем попыткой setState сделать это после того, как страница больше не находится в фокусе.

Этого можно избежать путем рефакторинга useEffect , например:

   useEffect(() => {
    // created a boolean to check if the component is mounted, name is arbitrary
    let mounted = true;

    const user = getUser();

    getUserById("/user/"   user.userId, user.token)
      .then((data) => {
        // only setState if mounted === true
        if (mounted) {
          setUserData(data);
          setLoaded(true);
        }
      })
      .catch((error) => {
        console.log(error);
      });

    // set mounted to false on cleanup
    return () => {
      mounted = false;
    };
  }, []);
 

Отличие здесь в том, что я использую mounted логическое значение для проверки того, смонтирована ли страница в данный момент. Заключив setState вызов в состояние if, я могу проверить , безопасно ли это setState , и таким образом избежать ошибки.

Дополнительное чтение

Ответ №3:

Это происходит, когда ваш компонент отключается перед настройкой состояния. Попробуйте выполнить этот код ниже, чтобы проверить, смонтирован компонент или нет.

 useEffect(() => {
  let isMounted = true;   // add a flag to check component is mounted

  getUserById("/user/"   user.userId, user.token)
  .then((data) => {
    if(mounted) {  // set state only when component is mounted
       setUserData(data)
       setLoaded(true)
    }
  })
  .catch((error) => {
    console.log(error)
  })

  return () => { isMounted = false }; // cleanup toggles value, if unmounted
}, []);
 

Ответ №4:

Не используйте асинхронные задачи в useEffect. Определите асинхронную функцию и вызовите свой эффект использования.

Пример:

 const getSTH = async() =>{
    getUserById("/user/"   user.userId, user.token)
     .then((data) => {
        if(mounted) {  // set state only when component is mounted
        setUserData(data)
        setLoaded(true)
     }
    })
    .catch((error) => {
       console.log(error)
    })

}

useEffect (()=>{
    getSTH();
},[])
 

Я думаю, что такой подход вам поможет.