У вас есть две проблемы управления состоянием и одна проблема с потоком выполнения, одна (или, возможно, больше) вызывает поведение, о котором вы упоминаете (но в любом случае все должны быть исправлены):
Обновления состояний асинхронные .Это означает, что this.state
имеет не обновленное состояние сразу после вызова this.setState
.
Поскольку обновления состояния являются асинхронными, если вы устанавливаете состояниеосновываясь на существующем состоянии (в котором вы находитесь в нескольких местах, включая switchLanguage
), вы должны использовать версию setState
, в которую вы передаете обратный вызов, а не версию, в которую вы передаете объект;в обратном вызове используйте актуальный объект состояния, который обратный вызов получает в качестве параметра.
Когда вы делаете this.setState({/*...*/desc: this.convertCode(/*...*/)})
, вы вызываете convertCode
перед тем вызов setState
и передача его возвращаемого значения в setState
в качестве значения свойства объекта, который вы передаете.Таким образом, даже если бы не проблема № 2, описанная выше, она все равно имела бы основную проблему с потоком контроля, и convertCode
по-прежнему видел бы устаревший this.state.lang
.
Лучший способ решить все это, вероятно, обновить convertCode
, чтобы дополнительно принять lang
для использования (по умолчанию this.state.lang
):
convertCode = (givenCode, lang = this.state.lang) => {
// ...use `lang`, not `this.state.lang`...
... а затем решить различные проблемы, задав состояние и используя convertCode
.Первая в componentDidMount
:
componentDidMount() {
this.setState({
isLoading: true
});
axios
.get("path to weather api")
.then(res => {
console.log(res.data.data[0]);
const { city_name, temp, weather } = res.data.data[0];
this.setState({
loc: city_name,
temp: temp,
code: weather.code,
isLoading: false
});
this.setState({
desc: this.convertCode(this.state.code) // <=== Error is here
});
});
}
this.state.code
еще не будет обновлена, поскольку обновления состояния являются асинхронными.Также мы хотим использовать this.state.lang
, поэтому нам нужно использовать форму обратного вызова.Вместо этого объедините эти два вызова и передайте язык convertCode
:
this.setState(prevState => ({
loc: city_name,
temp: temp,
code: weather.code,
isLoading: false,
desc: this.convertCode(weather.code, prevState.lang),
}));
В switchLanguage
существуют обе проблемы # 2 и # 3:
// INCORRECT:
// A) Sets state based on state without callback
// B) Calls `convertCode` before `setState`
switchLanguage = () => {
if (this.state.lang === "en") {
this.setState({
lang: "hi",
desc: this.convertCode(this.state.code)
});
} else {
this.setState({
lang: "en",
desc: this.convertCode(this.state.code)
});
}
};
Мы можем исправитьОбе проблемы с использованием формы обратного вызова и передачи языка для использования в convertCode
:
// Uses callback when setting state based on state
switchLanguage = () => {
this.setState(prevState => {
const lang = prevState.lang === "en" ? "hi": "en";
return {lang, desc: this.convertCode(prevState.code, lang)};
});
};
Обратите внимание на использование prevState
как для проверки lang
, так и для передачи code
в this.convertCode
.