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
相关产品推荐
相关产品推荐

