React子组件接收旧状态Props问题:多阶段注册表单数据传递异常
嘿,我看你遇到的问题是子组件拿不到父组件更新后的name props对吧?核心问题出在父组件初始化stage组件的时机上,咱们一步步来拆解和修复:
问题根源
你在父组件的constructor里定义了this.stage数组,这部分代码只会在组件实例化时执行一次。此时this.state.name还是初始的空字符串,所以<ContactMessage name={this.state.name} />的name props就被固定成空值了。后续父组件的name状态更新时,这个数组里的组件并不会重新生成,自然子组件接收不到新的props。
另外,你父组件里的几个setter方法还有个小bug:比如setName直接把事件对象e赋值给了state.name,而不是取e.target.value,这会导致你存的不是输入的文本,而是事件对象,也得一起修正。
修复方案
1. 把stage组件的定义移到render方法里
这样每次父组件state更新(不管是stage变化还是name/email等值变化),render都会重新执行,生成带有最新props的子组件。
修改后的父组件代码:
class ContactPage extends React.Component { constructor(props){ super(props); this.state = { stage:0, name:'', message:'', email:'', phone:'' } // 修正setter方法,取target.value this.setName=(e)=>{ this.setState({name:e.target.value}); } this.setMessage=(e)=>{ this.setState({message:e.target.value}); } this.setEmail=(e)=>{ this.setState({email:e.target.value}); } this.setPhone=(e)=>{ this.setState({phone:e.target.value}); } this.nextStage=()=>{ if(this.state.stage < 3){ this.setState({stage:this.state.stage+1}) } } this.previousStage=()=>{ if(this.state.stage >= 1){ this.setState({stage:this.state.stage-1}) } } } render(){ // 把stage组件移到render里,每次render都生成最新的组件 const stageComponents = [ <ContactName onChange={this.setName} />, {/* 补充ContactInfo的回调,不然父组件的email/phone状态没法更新 */} <ContactInfo onChangeEmail={this.setEmail} onChangePhone={this.setPhone} />, <ContactMessage name={this.state.name} onChange={this.setMessage} />, <Send /> ] return ( <div> {stageComponents[this.state.stage]} <button primary style={style.button} onClick={this.previousStage}> Previous </button> <button primary style={style.button} onClick={this.nextStage}> Next </button> </div> ) } }
2. 优化子组件ContactMessage
子组件里没必要把name存在自己的state里,直接用父组件传递的props.name就行。另外componentWillReceiveProps已经被React标记为过时,建议用componentDidUpdate替代(如果需要在props变化时做额外逻辑的话)。
修改后的子组件代码:
class ContactMessage extends React.Component { constructor(props){ super(props); this.state ={ message:'' } this.handleChange=(event)=>{ this.props.onChange(event.target.value); this.setState({message: event.target.value}); } // 记得绑定handleSubmit,如果用到的话 this.handleSubmit = this.handleSubmit.bind(this); } // 如果需要在name props变化时执行逻辑,用componentDidUpdate componentDidUpdate(prevProps) { if (prevProps.name !== this.props.name) { // 这里可以写props更新后的逻辑,比如打印或者其他操作 // 现在我们直接用props.name,所以不需要更新state了 } } handleSubmit(e) { e.preventDefault(); // 提交逻辑 } render(){ return( <div> {/* 直接使用props.name,不用再存到子组件state */} <h1>{this.props.name}</h1> <form onSubmit={this.handleSubmit}> <label htmlFor='messageField'> Message: <input className='messageField' type="textfield" value={this.state.message} onChange={this.handleChange} /> </label> </form> </div> ) } }
这样修改后,当你在第一阶段输入名字,点击Next进入第三阶段时,ContactMessage就能显示最新的name值啦。
内容的提问来源于stack exchange,提问作者Karolis Žukas

