React无状态子组件在父组件状态变更时不更新的问题求助
问题分析与解决思路
你遇到的问题核心在于**contentTypes对象中的组件实例是一次性创建的**——它定义在render()方法外部,只会在App组件初始化时生成一次。当父组件的searchContent状态更新后,这个预先创建好的<C/>组件并不会重新接收新的props,自然也就不会更新渲染。
另外,你的Field组件还有一个小bug:函数体没有返回JSX内容,这会导致该组件无法正常渲染。
下面是具体的修复方案:
方案1:将contentTypes改为组件工厂函数
把contentTypes从直接存储组件实例,改成存储返回组件的函数,这样每次render()时都会调用函数生成新的组件实例,确保传递最新的props:
class App extends Component { state = { contentType: "A", title: "Overview", searchContent: "" } tabHandler = (content, event) => { this.setState({ title: event.target.name, contentType: content }); } searchHandler = (event) => { this.setState({ searchContent: event.target.value }); } // 改成函数,每次调用返回新的组件实例 contentTypes = { A: () => <A/>, B: () => <B/>, C: () => <C onChange={this.searchHandler} content={this.state.searchContent}/> }; render() { return ( <div className="row"> <ul> <Tab click={this.tabHandler} id="A" name="A"/> <Tab click={this.tabHandler} id="B" name="B"/> <Tab click={this.tabHandler} id="C" name="C"/> </ul> <h1 id="title">{this.state.title}</h1> {/* 调用函数生成组件 */} {this.contentTypes[this.state.contentType]()} </div> ); } }
方案2:在render中直接动态渲染组件
如果你的标签类型不多,也可以直接在render()里通过条件判断渲染对应的组件,这样更直观,也能确保每次状态变化时都传递最新的props:
render() { let contentComponent; switch(this.state.contentType) { case "A": contentComponent = <A/>; break; case "B": contentComponent = <B/>; break; case "C": contentComponent = <C onChange={this.searchHandler} content={this.state.searchContent}/>; break; default: contentComponent = null; } return ( <div className="row"> <ul> <Tab click={this.tabHandler} id="A" name="A"/> <Tab click={this.tabHandler} id="B" name="B"/> <Tab click={this.tabHandler} id="C" name="C"/> </ul> <h1 id="title">{this.state.title}</h1> {contentComponent} </div> ); }
修复Field组件的渲染问题
你的Field组件当前没有返回JSX元素,而且label的props.value应该改为props.name(因为你传入的是name="search"),同时注意React事件采用驼峰式命名onChange,修正后:
import React from 'react'; const Field = (props) => { // 必须return JSX return ( <li className="field"> <input type="text" onChange={props.onChange} value={props.content} name={props.name} // 加上name属性,对应label的htmlFor /> <label htmlFor={props.name}>{props.name}</label> </li> ) } export default Field;
同时同步修改C组件中的事件传递:
import React from 'react' import Field from './form-builder/field'; const C = (props) => { return( <Field type="text" name="search" content={props.content} onChange={props.onChange}/> ); } export default C;
内容的提问来源于stack exchange,提问作者Hyperspace
相关产品推荐
相关产品推荐

