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

Next.js组件传值与API调用问题求助:ZipCode无法传递至子组件

问题分析与解决方案

我帮你梳理下代码里的几个关键问题,以及对应的修复步骤:

1. 表单提交错误清空了ZipCode值

你在handleSubmit里把zipCode设为空字符串了,这会导致提交后传给Forecast的props直接变成空,之前输入的内容就丢了:

handleSubmit = e => {
  e.preventDefault()
  // 这里不要清空state,而是可以标记提交状态
  // this.setState({zipCode: ''}); 
}

改成保留输入值,新增一个状态标记用户是否提交,这样后续可以根据这个状态触发API请求。

2. 子组件的getInitialProps不会自动执行

在Next.js中,getInitialProps只对pages目录下的页面组件生效,普通子组件(比如你的Forecast)的这个方法不会被Next.js自动调用,所以你的API请求根本没执行,这是拿不到数据的核心原因之一。

我们需要换一种方式:在Forecast组件中监听zipcode props的变化,当zipcode有有效值时再调用API。

3. 修复后的代码示例

修改Form.js

import React from 'react'
import Forecast from '../components/Forecast';
export default class Form extends React.Component {
  constructor(props) {
    super(props)
    this.state = { 
      zipCode: '',
      isSubmitted: false // 新增状态标记是否提交
    }
  }

  handleSubmit = e => {
    e.preventDefault()
    // 提交时标记状态,保留输入的zipCode
    this.setState({ isSubmitted: true });
  }

  render() {
    const { zipCode, isSubmitted } = this.state
    return (
      <div className="container">
        <div className="form-group">
          <h3 className="header">Enter your Zipcode</h3>
          <input 
            type="text" 
            className="form-control" 
            placeholder="Zipcode" 
            id="inputDefault" 
            value={zipCode} 
            onChange={e => this.setState({zipCode: e.target.value, isSubmitted: false})} // 输入时重置提交状态
          />
        </div>
        <button type="button" className="btn btn-success" onClick={this.handleSubmit}>Submit</button>
        <style jsx>{`
          body {
            height: 100vh;
            width: 100vw;
          }
          .header{
            color: #fff;
            font-weight: 600;
            font-family: 'Apercu', 'sans-serif';
          }
          div {
            margin-top: 300px;
          }
          @media (max-width: 600px) {
            div {
              background: blue;
            }
          }
        `}</style>
        {/* 只有提交且zipCode有值时,才渲染Forecast组件 */}
        {isSubmitted && zipCode && <Forecast zipcode={zipCode} />}
      </div>
    )
  }
}

修改Forecast.js

import React, {Component} from 'react'
import axios from 'axios';

export default class Forecast extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      weather: null,
      loading: false,
      error: null
    };
  }

  // 监听props变化,当zipcode更新且有值时调用API
  componentDidUpdate(prevProps) {
    if (this.props.zipcode && this.props.zipcode !== prevProps.zipcode) {
      this.fetchWeather();
    }
  }

  fetchWeather = async () => {
    this.setState({ loading: true, error: null });
    try {
      const res = await axios.get(`https://api.openweathermap.org/data/2.5/forecast?zip=${this.props.zipcode}&APPID=6f9e2f1d20bef61a529b8dbdb3fd82ae&units=metric`);
      this.setState({ weather: res.data, loading: false });
      console.log(res.data);
    } catch (err) {
      this.setState({ error: 'Failed to fetch weather data', loading: false });
      console.error(err);
    }
  }

  render() {
    const { weather, loading, error } = this.state;
    
    if (loading) return <div className="container--section-two"><p>Loading weather data...</p></div>;
    if (error) return <div className="container--section-two"><p>{error}</p></div>;

    return (
      <div className="container--section-two">
        <h1 className="header--section-two"> Here is your 5-day Forecast</h1>
        <div>
          <ul className="flex-wrapper">
            {/* 渲染5天的温度数据 */}
            {weather && weather.list.slice(0,5).map((item, index) => (
              <li key={index} className="flex-item">
                Day {index+1}<br/>
                {Math.round(item.main.temp)}°C
              </li>
            ))}
          </ul>
        </div>
        <style jsx>{`
          body {
            height: 100vh;
            width: 100vw;
          }
          .container--section-two{
            margin-top: 500px;
          }
          .header--section-two{
            color: #fff;
            font-family: 'Tiempos Headline', sans-serif;
            font-style: normal;
            font-weight: 300;
          }
          .flex-wrapper {
            padding: 0;
            margin: 0;
            list-style: none;
            display: -webkit-box;
            display: -moz-box;
            display: -ms-flexbox;
            display: -webkit-flex;
            display: flex;
            -webkit-flex-flow: row wrap;
            justify-content: space-around;
          }
          .flex-item {
            background: rgba(255, 255, 255, 0.4);
            padding: 5px;
            width: 200px;
            height: 250px;
            margin-top: 10px;
            line-height: 50px;
            color: #fff;
            font-weight: bold;
            font-size: 1.5em;
            text-align: center;
            box-shadow: 0 2px 8px 0 #fff;
          }
          div {
            margin-top: 60px;
            margin-bottom: 250px;
          }
          @media (max-width: 600px) {
            div {
              background: blue;
            }
          }
        `}</style>
      </div>
    )
  }
}

额外注意事项

  • 不要把API密钥硬编码在前端代码里,这会泄露你的密钥!建议把API请求放在Next.js的API路由(pages/api目录下),前端调用自己的API路由,再由后端转发请求到OpenWeatherMap,这样密钥就不会暴露。
  • 可以给ZipCode输入框加验证(比如只能输入数字,长度符合美国邮编格式),避免无效请求。

内容的提问来源于stack exchange,提问作者Natasha Kelly

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:55:32