#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. К сожалению, ваше первое решение не сработало для меня. Состояние по-прежнему не обновляется