Состояние реакции не обновляется после вызова API

#reactjs #setstate

#reactjs #setstate

Вопрос:

Я пытаюсь установить состояние после вызова API, и я знаю, что это асинхронная задача, но я не могу понять, как обновить мое состояние. Мой код выглядит так:

 loadUserDetails = () => {
    this.setState({
        isLoading: true,
        status: "Fetching user details..."
    }, () => {
        fetch('url', { method: 'Get', credentials: 'include' })
            .then(res => res.json())
            .then((data) => {
                console.log("results")
                console.log(data.name);
                console.log(data.surname);
                console.log(data.emailAddress);
                this.setState({
                    userProfile: data
                })
                if (this.state.userProfile != null)
                    this.loadRolesData();
                })
            })
        });
        .catch(console.log);
}
 

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

Редактировать:

Я инициирую это из componentDidMount(). Я думаю, что это правильное место, но рад, что мне сказали иначе.

Ответ №1:

Я думаю, вы выполнили задачу в неправильном порядке.

Сделайте fetch для api, затем сделайте setState . Вот один простой пример.

   fetch(...).then(res => {
    this.setState({...})
  })
 

Пожалуйста, не запутывайтесь во втором параметре setState , то есть дождаться завершения обновления состояния. Обычно это предназначено для какого-то особого случая, в 99% случаев вам это не нужно.

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

1. Он сделал это в правильном порядке. Во-первых setState , для установки isLoading флага true. В обратном вызове then() для фактических данных есть второй.

2. Вам не кажется, что это немного безумно, почему бы не начать с флага без вызова setState ? const [a] = useState(false)

3. Он, очевидно, не знает, как использовать реагирующие хуки. Да, я согласен, даже без перехватов реакции нет реальной необходимости вызывать fetch() только после установки флага загрузки, потому что это не зависит от него, но это было в его исходном коде, и вы его неправильно поняли.

Ответ №2:

setState не обновляет состояние сразу после вызова, и именно поэтому существует второй аргумент (обратный вызов). Он запускается только после завершения обновления. На самом деле вы использовали этот второй аргумент в своем первом setState вызове. Таким образом, вы можете либо сделать то же самое во втором вызове:

 this.setState({
  isLoading: true,
  status: "Fetching user details..."
}, () => {
  fetch('url', { method: 'Get', credentials: 'include' })
    .then(res => res.json())
    .then((data) => {
      console.log("results")
      console.log(data.name);
      console.log(data.surname);
      console.log(data.emailAddress);
      this.setState({
        userProfile: data
      }, () => {
        // this code will get fired only after the state updates
        if (this.state.userProfile != null) {
          this.loadRolesData();
        }
      })
    })
    .catch(console.log);
});
 

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

 const [userProfile, setUserProfile] = React.useState(null);
const [isLoading, setIsLoading] = React.useState(false);

// This function will get fired every time the userProfile state updates
React.useEffect(() => {
  if (userProfile != null) {
    loadRolesData();
  }
}, [userProfile]);

const loadUserProfile = () => {
  setIsLoading(true);
  setStatus("Fetching user details...");
  fetch('url', { method: 'Get', credentials: 'include' })
    .then(res => res.json())
    .then((data) => {
      console.log("results")
      console.log(data.name);
      console.log(data.surname);
      console.log(data.emailAddress);
      setUserProfile(data);
      setIsLoading(false);
    })
    .catch(console.log);
};
 

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

1. К сожалению, ваше первое решение не сработало для меня. Состояние по-прежнему не обновляется