【问题标题】:How to re-render the same component on React?如何在 React 上重新渲染相同的组件?
【发布时间】:2020-12-28 10:22:53
【问题描述】:

我正在使用 api 制作这个天气应用程序。所以,首先我必须显示一个默认城市的天气。然后当我选择其他城市时,该组件将再次呈现给我所选城市的天气数据。 到目前为止,我已经完成了我的项目:

const initialDivisionId = "3";

const getDivision = (divisionId) => {
  return divisions.find((division) => division.id === divisionId);
};

class Weather extends React.Component {
  constructor(props) {
    super(props);
    const division = getDivision(initialDivisionId);
    this.state = {
      divisionId: initialDivisionId,
      lat: division.lat,
      long: division.long,
      currentWeatherData: [],
      hourlyWeatherData: [],
      dailyWeatherData: []
    };
  }

  onDivisionChange = (event) => {
    const divisionId = event.target.value;
    const { lat, long } = getDivision(divisionId);

    this.setState({
      divisionId: event.target.value,
      lat: lat.lat,
      long: long.long
    });
    
  };

  componentDidMount() {
    fetch(
      `https://api.openweathermap.org/data/2.5/onecall?lat=${this.state.lat}&lon=${this.state.long}&units=metric&exclude=alerts&appid={api_key}`
    )
      .then((res) => res.json())
      .then(
        (result) => {
          this.setState({
            currentWeatherData: result.current,
            hourlyWeatherData: result.hourly[0],
            dailyWeatherData: result.daily[0]
          });
        },
        (error) => {
          console.log(error);
          this.setState({
            error
          });
        }
      );
  }

  render() {
    console.log(this.state.currentWeatherData);
    console.log(this.state.hourlyWeatherData);
    console.log(this.state.dailyWeatherData);
    return (
      <div>
        <Title />

        <Select
          variant="filled"
          w="30%"
          placeholder="Select option"
          value={this.state.divisionId}
          onChange={this.onDivisionChange}
        >
          {divisions.map((division) => (
            <option key={division.id} value={division.id}>
              {division.name}
            </option>
          ))}
        </Select>
        <div>
          <Stack spacing={6}>
            <Heading color="tomato" size="4xl">
              {this.state.currentWeatherData.dt}
            </Heading>

            <Heading color="gray" size="3xl">
              {this.state.currentWeatherData.temp}
            </Heading>

            <Heading color="blue" size="2xl">
              {this.state.hourlyWeatherData.pressure}
            </Heading>

            <Heading color="black" size="xl">
              {this.state.hourlyWeatherData.temp}
            </Heading>

            <Heading color="black" size="lg">
              {this.state.dailyWeatherData.clouds}
            </Heading>

            <Heading color="yellow" size="md">
              {this.state.dailyWeatherData.humidity}
            </Heading>
          </Stack>
        </div>
      </div>
    );
  }
}

const Title = () => {
  return (
    <Text align="center">
      <Heading size="xl">Weather App</Heading>
    </Text>
  );
};

function App() {
  return (
    <ChakraProvider>
      <Weather />
    </ChakraProvider>
  );
}

export default App;

所以,我知道如果我想重新渲染,我必须使用 shouldComponentUpdate 生命周期方法。如果我想要其他城市的天气响应,如何重新渲染相同的组件?还是我需要将状态作为道具传递给其他组件,然后我必须获取 api?需要帮助!

【问题讨论】:

  • 如果你设置了状态,组件应该重新渲染,而不需要你做任何其他事情。您是否尝试过使用新的城市信息设置状态?
  • 这是什么意思?每当状态发生变化时,您的组件都会重新渲染..
  • 每次调用this.setState,组件都会重新渲染,如果根据更改的数据发生DOM更改。
  • 啊,我看到了你的问题,你的 API 调用只在 componentDidMount,所以它只会在你的组件挂载时获取数据。你想要做的也是把它放在componentDidUpdate 中。为了尽量避免冗余代码,你可以把它放在自己的方法中。
  • @Nick 好的,所以 fetch 应该在 componentDidmount 内?

标签: javascript reactjs react-lifecycle


【解决方案1】:

您遇到的问题不是您需要重新渲染组件,而是您需要在状态更新时点击天气 API。您可以通过确保在 componentDidUpdate 生命周期方法中调用 API 来做到这一点。这是一些更新的代码(并抽象了 API 调用以避免冗余代码)。

fetchWeatherData() {
  fetch(`https://api.openweathermap.org/data/2.5/onecall?lat=${this.state.lat}&lon=${this.state.long}&units=metric&exclude=alerts&appid={api_key}`
  )
    .then((res) => res.json())
    .then(
      (result) => {
        this.setState({
          currentWeatherData: result.current,
          hourlyWeatherData: result.hourly[0],
          dailyWeatherData: result.daily[0]
        });
      },
      (error) => {
        console.log(error);
        this.setState({
          error
        });
      }
    );
}

componentDidMount() {
  this.fetchWeatherData();
}

componentDidUpdate(_, prevState) {
  if (prevState.lat !== this.state.lat || prevState.long !== this.state.long) {
    this.fetchWeatherData();
  }
}

在构造函数中,确保将fetchWeatherData绑定到this

constructor(props) {
  // Existing constructor code here
  this.fetchWeatherData = this.fetchWeatherData.bind(this);
}

【讨论】:

  • 它会抛出一个Unhandled Runtime Error TypeError: Cannot read property '0' of undefined
  • 您可能需要在 fetch 调用的返回中进行一些故障排除。该错误告诉我在某些时候从您的 fetch 调用返回中没有result.hourlyresult.daily。例如,如果您提供错误的纬度/经度,API 是否会返回不同类型的返回值?
  • (还要确保正确包含 API 密钥。现在我将它复制到问题中的方式,但看起来它应该是模板文字变量 ${api_key} 而不是它目前是(没有美元符号)
  • 我显然输入了正确的api密钥。但是我认为当我选择该选项时,响应可能会出现一些问题。必须努力。
  • 你这里的代码无限循环,让我朋友注意到了。
猜你喜欢
  • 2017-05-17
  • 2021-12-15
  • 2020-09-29
  • 1970-01-01
  • 2021-06-07
  • 1970-01-01
  • 2019-08-10
  • 1970-01-01
  • 2021-06-19
相关资源
最近更新 更多