React如何正确向props中的函数传递参数?CV应用开发实践问题
问题原因
你当前功能异常的核心是子组件调用父组件方法时传参顺序错误、缺失事件对象:
- 父组件
handleJobChange要求第一个参数是事件对象e,第二个是id - 子组件调用时只传了
id,把事件对象漏了,导致e.target无法正常读取
修正方案
1. 修正Job子组件的onChange传参
把所有input的onChange回调统一修改为同时传递事件对象和id:
import React from 'react' class Job extends React.Component{ constructor(props){ super(props) } render(){ return( <div id={this.props.id}> <label htmlFor='company'>Company:</label> <input name='company' onChange={(e)=>this.props.onJobChange(e, this.props.id)} /> <label htmlFor='position'>Position:</label> <input name='position' onChange={(e)=>this.props.onJobChange(e, this.props.id)} /> <label htmlFor='tasks'>Tasks:</label> <input name='tasks' onChange={(e)=>this.props.onJobChange(e, this.props.id)} /> <label htmlFor='start'>Date from:</label> <input name='start' onChange={(e)=>this.props.onJobChange(e, this.props.id)} /> <label htmlFor='until'>Date until:</label> <input name='until' onChange={(e)=>this.props.onJobChange(e, this.props.id)} /> </div> ) } } export default Job
注意:React中label的for属性要写为htmlFor,避免原生属性冲突
2. 修正App组件的不规范写法
同步优化现有代码里不符合React开发规范的部分:
import React from 'react'; import Bio from './components/Bio' import CV from './components/CV' import Job from './components/Job' class App extends React.Component { constructor() { super() // 已用箭头函数定义的方法不需要在constructor里手动绑定this,箭头函数会自动绑定当前实例 this.state = { bio_state: {name:'', phone:'', email:''}, job: [{id:this.idGen(), company:'', position:'',tasks:'', start:'', until:''}] } } idGen() { return Math.random().toString(36).replace(/[^a-z]+/g, '').substr(2, 10); } handleBioChange = (e) => { // 遵循不可变数据原则,不要直接修改原state,先浅拷贝再更新 this.setState({ bio_state: {...this.state.bio_state, [e.target.name]: e.target.value} }) } addJob = () => { // 依赖之前的state做更新时,必须用函数式setState,避免状态更新不同步的问题 this.setState(prev => ({ job: [...prev.job, {id:this.idGen(), company:'', position:'',tasks:'', start:'', until:''}] })) } // 该方法本身的更新逻辑是正确的,只要子组件传参正确即可正常运行 handleJobChange = (e, id) => { this.setState(previousState => { const jobList = [...previousState.job] const targetIndex = jobList.findIndex(item => item.id === id) jobList[targetIndex] = {...jobList[targetIndex], [e.target.name]: e.target.value} return { job: jobList } }) } render() { return ( <div> <Bio onBioChange={this.handleBioChange} /> { this.state.job.map((item) => ( // map渲染列表必须加key属性,避免React渲染警告和异常 <Job key={item.id} id={item.id} onJobChange={this.handleJobChange}/> )) } <CV name={this.state.bio_state.name} phone={this.state.bio_state.phone} email={this.state.bio_state.email} jobs={this.state.job}/> </div> ) } }
方案说明
当前这种多字段列表的状态更新写法已经是常规最佳实践:
- 用唯一id标识每个列表项,避免依赖索引更新带来的渲染bug
- 遵循不可变数据原则,每次更新都生成新的数组/对象,不直接修改原state
- 子组件只负责触发回调、传递必要参数,状态更新逻辑全部收敛在父组件,符合React单向数据流原则
内容的提问来源于stack exchange,提问作者Lars Plotner
相关产品推荐
相关产品推荐

