Переключить язык с помощью React без Redux - PullRequest
0 голосов
/ 21 сентября 2018

Я пытаюсь создать приложение погоды в React.Я хочу переключить язык приложения с помощью onClick.

Вот мой код.

import React, { Component } from "react";
import axios from "axios";
import "./App.css";

class App extends Component {

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)
        });
      });
  }

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 = givenCode => {
    if (this.state.lang === "en") {
      if (
        givenCode === 200 ||
        givenCode === 201 ||
        givenCode === 202 ||
        givenCode === 230 ||
        givenCode === 231 ||
        givenCode === 232 ||
        givenCode === 233 ||
        givenCode === "200" ||
        givenCode === "201" ||
        givenCode === "202" ||
        givenCode === "230" ||
        givenCode === "231" ||
        givenCode === "232" ||
        givenCode === "233"
      ) {
        return "Thunderstorms";
      } else if (
        givenCode === 300 ||
        givenCode === 301 ||
        givenCode === 302 ||
        givenCode === "300" ||
        givenCode === "301" ||
        givenCode === "302"
      ) {
        return "Drizzle";
      }
      ..............
      ..............
      IF CONDITION FOR THE OTHER LANGUAGE
  };

render() {
    if (!this.state.isLoading) {
      return (
        <div className="App">
          <div className="container">
            <div className="languageSwitcher">
              <i className="fa fa-language" onClick={this.switchLanguage} />
            </div>
            <div className="location">
              <i className="fa fa-location-arrow" /> {this.state.loc}
            </div>
            {this.state.lang === "en" && (
              <div className="temperature">It's {this.state.temp} degrees.</div>
            )}
            {this.state.lang === "hi" && (
              <div className="temperature">
                तापमान {this.state.temp} डिग्री है।
              </div>
            )}
            <div className="description">{this.state.desc}</div>
          </div>
        </div>
      );
    } else {
      return <div className="loading">Fetching weather data...</div>;
    }
  }
}

export default App;

Все работает, кроме div с className="desc".desc всегда на одну фазу позади.Я имею в виду, когда state.lang равен en, он отображает текст в hi и наоборот.

Я только начал изучать React, поэтому код довольно запутался.Извините за это.

Спасибо.

Ответы [ 2 ]

0 голосов
/ 21 сентября 2018

Вы используете предыдущее состояние lang в методе convertCode, вместо этого вы можете передать ему новый lang:

convertCode = (givenCode, lang) => {
    if (lang === "en") {
        ...

Затем в вашем методе switchLanguage:

this.setState({
        lang: "hi",
        desc: this.convertCode(this.state.code, "hi")
      });

Редактировать : предпочитайте функциональную версию setState, чтобы избежать несоответствий в случае this.state.code обновлений:

this.setState(prevState => ({
        lang: "hi",
        desc: this.convertCode(prevState.code, "hi")
      }));
0 голосов
/ 21 сентября 2018

У вас есть две проблемы управления состоянием и одна проблема с потоком выполнения, одна (или, возможно, больше) вызывает поведение, о котором вы упоминаете (но в любом случае все должны быть исправлены):

  1. Обновления состояний асинхронные .Это означает, что this.state имеет не обновленное состояние сразу после вызова this.setState.

  2. Поскольку обновления состояния являются асинхронными, если вы устанавливаете состояниеосновываясь на существующем состоянии (в котором вы находитесь в нескольких местах, включая switchLanguage), вы должны использовать версию setState, в которую вы передаете обратный вызов, а не версию, в которую вы передаете объект;в обратном вызове используйте актуальный объект состояния, который обратный вызов получает в качестве параметра.

  3. Когда вы делаете 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.

...