React父子组件传值异常:子组件未更新Domain选项列表
你的问题核心在于:父组件AddQuestion切换课程后更新了domains状态,但已经生成的SubQuestion组件没有接收到最新的domains props。这是因为你在addSubQuestion方法中一次性生成了subQuestions数组并存在state里,之后父组件的domains变化时,没有重新更新这些子组件的props。另外代码里还有几处state操作的错误,一起帮你修正:
1. 修复父组件AddQuestion中getResponseDomains的state操作错误
你在这个方法里直接修改this.state.domains = json;,还在map里多次调用setState,这都是不符合React state更新规范的,会导致状态更新混乱。正确的做法是先处理好数据,再一次性更新state:
getResponseDomains = () => { console.log(this.state.course); axios.get('/api/domain/get?course=' + this.state.course) .then(response => response.data.data) .then((json) => { // 直接处理所有数据生成options,不要直接修改state const domainslist = Object.values(json).map(domain => <option key={domain.id} label={domain.name} value={domain.id} /> ); this.setState({ domains: domainslist }); // 同时更新subQuestions,让子组件拿到新的domains this.updateSubQuestions(); }) .catch((error) => { console.log(error); }); }
2. 新增updateSubQuestions方法,在domains变化时更新子组件props
原来的addSubQuestion只在点击按钮时生成子组件,现在需要一个方法,在domains更新后重新生成subQuestions数组,让每个SubQuestion都拿到最新的domains:
updateSubQuestions = () => { const subQuestions = []; for (let i = 0; i <= this.state.numSubQuestion; i += 1) { subQuestions.push( <SubQuestion key={i} number={i + 1} course={this.state.course} domains={this.state.domains} subjects={this.state.subjects} // 别忘了把其他需要的props传进去,比如各类事件处理方法 handleSubjectChange={this.handleSubjectChange} handleTimeChange={this.handleTimeChange} handlePointsChange={this.handlePointsChange} handleRttiChange={this.handleRttiChange} validateForm={this.validateForm} /> ); } this.setState({ subQuestions }); }
3. 修改addSubQuestion方法,调用updateSubQuestions
原来的addSubQuestion里手动生成数组的逻辑可以替换成调用上面的方法,保持逻辑统一:
addSubQuestion = () => { this.setState({ numSubQuestion: this.state.numSubQuestion + 1, formHasError: true }, () => { // 状态更新后再更新子组件 this.updateSubQuestions(); }); }
4. 优化子组件SubQuestion的生命周期方法
componentWillReceiveProps已经被废弃,建议使用componentDidUpdate来处理props变化:
componentDidUpdate(prevProps) { // 当domains或course变化时更新子组件state if (prevProps.domains !== this.props.domains || prevProps.course !== this.props.course) { this.setState({ course: this.props.course, domains: this.props.domains }); } }
另外,子组件里的getResponseSubjects也有直接修改this.state.subjects = json;的错误,同样要改成先处理数据再setState:
getResponseSubjects = () => { axios.get('/api/subject/get?domain=' + this.state.domain) .then(response => response.data.data) .then((json) => { const subjectslist = Object.values(json).map(subject => <option key={subject.id} label={subject.name} value={subject.id} /> ); this.setState({ subjects: subjectslist }); }) .catch((error) => { console.log(error); }); }
为什么原来的代码不工作?
你最初的实现中,subQuestions数组是在点击"添加子问题"按钮时生成并存在state里的,之后父组件的domains变化时,这个数组里的SubQuestion组件的props并没有被更新——因为React只会在state或props变化时重新渲染,而你没有重新生成这个数组,所以子组件拿不到新的domains。通过新增updateSubQuestions方法,在domains变化和添加子问题时都重新生成子组件数组,就能保证每个子组件都拿到最新的props了。
内容的提问来源于stack exchange,提问作者Jordy Senssen

