React子组件受控输入报错:已加onChange仍提示无处理函数
问题描述
我尝试在子组件(Search组件)中设置受控输入,希望将输入状态保留在主App组件中,以便在apiCall方法中访问。但出现如下错误:
Warning: You provided a
<code>value</code>prop to a form field without an<code>onChange</code>handler. This will render a read-only field. If the field should be mutable use<code>defaultValue</code>. Otherwise, set either<code>onChange</code>or<code>readOnly</code>.
我已经添加了onChange处理函数,推测问题出在该函数位于父组件中。将输入移到主App组件中时可正常运行(能在控制台打印输入内容)。
我的实现方式是否有误?有没有办法实现在App组件中访问Search组件的输入,同时将大部分代码、函数和状态保留在主App组件中?
App组件代码
import React, { Component } from "react"; import './App.css'; import Header from './Components/Header' import Search from './Components/Search' import MainInfo from './Components/MainInfo' import Details from './Components/Details' class App extends React.Component { constructor(props) { super(props); this.state = { weather: null, main: '', wind: '', loading: null, cityInput: 'Houston', city: 'City Name', date: new Date() }; this.apiCall = this.apiCall.bind(this); this.handleChange = this.handleChange.bind(this); } handleChange(event) { this.setState({ cityInput: event.target.value }) console.log(this.state.cityInput) } // Fetch data from OpenWeatherAPI apiCall() { this.setState({ loading: true }) const currentWeather = fetch( `https://api.openweathermap.org/data/2.5/weather?q=${this.state.cityInput}&appid={apiKey}&units=imperial` ).then((res) => res.json()); const futureWeather = fetch( `https://api.openweathermap.org/data/2.5/forecast?q=houston&appid={apiKey}&units=imperial` ).then((res) => res.json()); const allData = Promise.all([currentWeather, futureWeather]); // attach then() handler to the allData Promise allData.then((res) => { this.setState({ weather: res[0].weather, main: res[0].main, wind: res[0].wind, city: res[0].name }) }); } componentDidMount() { this.apiCall(); } render() { return ( <div className="container-fluid bg-primary vh-100 vw-100 d-flex flex-column align-items-center justify-content-around p-3"> <Header /> <Search cityInput={this.state.cityInput} /> <MainInfo main={this.state.main} date={this.state.date} city={this.state.city} weather={this.state.weather} /> <Details main={this.state.main} wind={this.state.wind} /> </div> ); } } export default App;
Search组件代码
import React, { Component } from "react"; class Search extends Component { constructor(props) { super(props); } render() { return ( <div className="row"> <div className="col-12"> <div className="d-flex"> <input className="form-control shadow-none mx-1" placeholder="Enter a city..." value={this.props.cityInput} onChange={this.handleChange}></input> <button className="btn btn-light shadow-none mx-1" onClick={this.apiCall}>Test</button></div> </div> </div> ); } } export default Search;
问题原因与解决办法
核心问题
你在Search组件中调用了this.handleChange和this.apiCall,但这两个方法属于App组件,并没有通过props传递给Search组件——Search组件内部找不到这两个函数,等同于输入框没有有效的onChange处理逻辑,因此触发了警告。
修改步骤
- 在App组件中传递方法给Search组件
修改App组件render方法里的Search标签,将handleChange和apiCall作为props传入:
<Search cityInput={this.state.cityInput} handleChange={this.handleChange} apiCall={this.apiCall} />
- 在Search组件中使用props中的方法
修改Search组件的输入框和按钮的事件绑定,改为调用props中的方法:
<input className="form-control shadow-none mx-1" placeholder="Enter a city..." value={this.props.cityInput} onChange={this.props.handleChange} /> <button className="btn btn-light shadow-none mx-1" onClick={this.props.apiCall} >Test</button>
额外优化建议
futureWeather接口中硬编码了q=houston,建议改为使用this.state.cityInput,确保搜索其他城市时未来天气数据同步更新:
const futureWeather = fetch( `https://api.openweathermap.org/data/2.5/forecast?q=${this.state.cityInput}&appid={apiKey}&units=imperial` ).then((res) => res.json());
setState是异步操作,handleChange中直接console.log(this.state.cityInput)可能打印旧值,若需查看更新后的状态,可使用setState的回调函数:
handleChange(event) { this.setState({ cityInput: event.target.value }, () => { console.log(this.state.cityInput) }) }
内容的提问来源于stack exchange,提问作者rileylitchfield
相关产品推荐
相关产品推荐

