You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React实现温度单位切换:当前天气与预报同步更新方案

温度单位同步切换的React实现方案

问题描述

我正在学习React,现有两个组件:ForecastDay用于展示预报的最高、最低温度,WeatherTempUnit实现温度单位(°C/°F)切换功能。目前点击切换单位时,仅单个组件的温度显示变化,希望实现点击切换后,当前天气和所有预报温度同步切换单位,求可行的实现方案(如状态提升、修改API请求参数等)。

原组件代码

ForecastDay组件

import React from "react";
import WeatherIcon from "./WeatherIcon";
export default function ForecastDay(props) {
  function showMax() {
    let max = Math.round(props.data.temperature.maximum);
    return max;
  }
  function showMin() {
    let min = Math.round(props.data.temperature.minimum);
    return min;
  }
  function showDay() {
    let date = new Date(props.data.time * 1000);
    let days = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
    let day = days[date.getDay()];
    return day;
  }

  return (
    <div className="waether-forcast">
      <div className="forecast-date">{showDay()}</div>

      <div>
        <WeatherIcon code={props.data.condition.icon} size={43} />
      </div>
      <div>
        <strong>
          <span>{showMax()}</span>
        </strong>
        °<span> {showMin()}°</span>
      </div>
    </div>
  );
}

WeatherTempUnit组件

export default function WeatherTempUnit(props) {
  const [unit, setUnit] = useState("celsius");
  function showFarn(event) {
    event.preventDefault();
    setUnit("fahrenheit");
  }
  function showCel(event) {
    event.preventDefault();
    setUnit("celsius");
  }
  function fahrenheit() {
    return Math.round((props.celsius * 9) / 5 + 32);
  }
  if (unit === "celsius") {
    return (
      <div>
        <span>{props.celsius}</span>
        <span className="units">
          °C |{" "}
          <a href="/" onClick={showFarn}>
            °F
          </a>
        </span>
      </div>
    );
  } else {
    return (
      <div>
        <span>{fahrenheit()}</span>
        <span className="units">
          <a href="/" onClick={showCel}>
            °C{" "}
          </a>
          | °F
        </span>
      </div>
    );
  }
}

可行实现方案

方案一:状态提升(React标准解决方案)

把温度单位的状态从WeatherTempUnit组件提升到当前天气和预报列表的共同父组件,让所有需要根据单位切换显示的组件共享同一个状态。

实现步骤

  1. 在父组件中定义单位状态和切换方法
  2. 将单位状态和切换方法通过props传递给WeatherTempUnit和所有ForecastDay组件
  3. 修改两个子组件,根据传入的单位状态计算显示对应的温度

修改后的代码示例

父组件(如WeatherApp)
import React, { useState } from "react";
import WeatherTempUnit from "./WeatherTempUnit";
import ForecastDay from "./ForecastDay";

export default function WeatherApp() {
  // 父组件统一维护单位状态
  const [unit, setUnit] = useState("celsius");

  // 单位切换方法,传递给子组件调用
  const toggleUnit = (newUnit) => {
    setUnit(newUnit);
  };

  // 示例天气数据(实际从API获取)
  const currentTemp = 22;
  const forecastData = [
    {
      time: 1699996800,
      temperature: { maximum: 25, minimum: 18 },
      condition: { icon: "sunny" }
    },
    // 更多预报数据...
  ];

  return (
    <div className="weather-app">
      {/* 传递单位状态和切换方法给WeatherTempUnit */}
      <WeatherTempUnit celsius={currentTemp} unit={unit} toggleUnit={toggleUnit} />
      
      {/* 遍历预报数据,传递单位状态给每个ForecastDay */}
      <div className="forecast-container">
        {forecastData.map((dayData, index) => (
          <ForecastDay key={index} data={dayData} unit={unit} />
        ))}
      </div>
    </div>
  );
}
修改后的WeatherTempUnit组件
import React from "react";

export default function WeatherTempUnit(props) {
  function showFarn(event) {
    event.preventDefault();
    props.toggleUnit("fahrenheit");
  }

  function showCel(event) {
    event.preventDefault();
    props.toggleUnit("celsius");
  }

  function fahrenheit() {
    return Math.round((props.celsius * 9) / 5 + 32);
  }

  if (props.unit === "celsius") {
    return (
      <div>
        <span>{props.celsius}</span>
        <span className="units">
          °C |{" "}
          <a href="/" onClick={showFarn}>
            °F
          </a>
        </span>
      </div>
    );
  } else {
    return (
      <div>
        <span>{fahrenheit()}</span>
        <span className="units">
          <a href="/" onClick={showCel}>
            °C{" "}
          </a>
          | °F
        </span>
      </div>
    );
  }
}
修改后的ForecastDay组件
import React from "react";
import WeatherIcon from "./WeatherIcon";

export default function ForecastDay(props) {
  // 根据父组件传递的单位计算温度
  function showMax() {
    let max = props.data.temperature.maximum;
    if (props.unit === "fahrenheit") {
      max = Math.round((max * 9) / 5 + 32);
    } else {
      max = Math.round(max);
    }
    return max;
  }

  function showMin() {
    let min = props.data.temperature.minimum;
    if (props.unit === "fahrenheit") {
      min = Math.round((min * 9) / 5 + 32);
    } else {
      min = Math.round(min);
    }
    return min;
  }

  function showDay() {
    let date = new Date(props.data.time * 1000);
    let days = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
    let day = days[date.getDay()];
    return day;
  }

  return (
    <div className="waether-forcast">
      <div className="forecast-date">{showDay()}</div>
      <div>
        <WeatherIcon code={props.data.condition.icon} size={43} />
      </div>
      <div>
        <strong>
          <span>{showMax()}</span>°
        </strong>
        <span> {showMin()}°</span>
      </div>
    </div>
  );
}

方案二:修改API请求参数(后端切换单位)

如果你的天气API支持直接返回不同单位的温度数据,可以在切换单位时重新请求API,获取对应单位的温度后更新所有组件的数据源。

实现步骤

  1. 在父组件中维护单位状态和天气数据状态
  2. 切换单位时,携带对应单位参数重新请求API
  3. 将新的天气数据传递给所有子组件直接显示

关键代码示例(父组件)

import React, { useState, useEffect } from "react";
import WeatherTempUnit from "./WeatherTempUnit";
import ForecastDay from "./ForecastDay";

export default function WeatherApp() {
  const [unit, setUnit] = useState("celsius");
  const [weatherData, setWeatherData] = useState(null);

  // 单位变化时重新请求API
  useEffect(() => {
    // 假设API支持units参数,值为celsius/fahrenheit
    fetch(`https://your-weather-api.com/data?units=${unit}`)
      .then(res => res.json())
      .then(data => {
        setWeatherData(data);
      });
  }, [unit]);

  const toggleUnit = (newUnit) => {
    setUnit(newUnit);
  };

  if (!weatherData) return <div>加载中...</div>;

  return (
    <div className="weather-app">
      <WeatherTempUnit 
        celsius={weatherData.current.temp} 
        unit={unit} 
        toggleUnit={toggleUnit} 
      />
      <div className="forecast-container">
        {weatherData.forecast.map((dayData, index) => (
          <ForecastDay key={index} data={dayData} />
        ))}
      </div>
    </div>
  );
}

这种方式下,ForecastDay组件无需修改温度计算逻辑,直接显示API返回的对应单位温度即可。


方案对比

  • 状态提升:无需额外API请求,前端完成温度转换,适合API不支持单位切换或希望减少请求的场景,是React状态共享的标准做法。
  • 修改API参数:前端逻辑更简洁,温度转换由后端处理,数据准确性更高,适合API支持单位参数的场景。

内容的提问来源于stack exchange,提问作者Fox Black

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 21:12:16