React父子组件传值异常:多次点击按钮后数值更新不符预期
父子组件传值异常问题分析
问题描述
父组件向子组件传递一个数值,子组件点击按钮后给该数值加3并传回父组件,父组件给传回的数值加100后,再传递给子组件。但实际运行时,第一次点击输出104,从第二次点击开始数值仅增加3,而非预期的每次增加103。
问题代码
class Parent2 extends React.Component { constructor(props) { super(props); this.state = { msgFromOut: props.out, }; } getChildMsg = (data) => { console.log("get the msg from child component data is ", data); this.setState({ msgFromOut: 100 + data, }); }; render() { return ( <div className="parent"> this is father <Child2 getMsg={this.getChildMsg} outerMsg={this.state.msgFromOut} /> <h1>{this.state.msgFromOut}</h1> </div> ); } } class Child2 extends React.Component { constructor(props) { super(props); console.log("child is getting", props); this.state = { msgFromFather: props.outerMsg, }; } handleClick = () => { this.setState( { msgFromFather: this.state.msgFromFather + 3, }, () => { this.props.getMsg(this.state.msgFromFather); } ); }; render() { return <button onClick={this.handleClick}>to father</button>; } } reactDom.render(<Parent2 out={1} />, document.querySelector("#root3"));
原因分析
- 子组件
Child2的msgFromFather状态只在构造函数中初始化了一次,后续父组件更新outerMsg传递新值时,子组件并没有同步更新自身的msgFromFather状态。 - 第一次点击流程:父组件初始值1 → 子组件初始化
msgFromFather为1 → 加3后变成4传给父组件 → 父组件加100得到104。此时父组件状态更新,但子组件的msgFromFather仍停留在4。 - 第二次点击流程:子组件基于自身状态4加3得到7 → 传给父组件加100得到107,看起来只增加了3(104→107),本质是子组件没有用父组件最新传递的数值计算。
解决方案
有两种常见的解决方式:
方式一:子组件直接使用父组件props,不维护自身状态
既然子组件的数值完全依赖父组件传递的值,没必要单独维护状态,直接用props.outerMsg计算即可:
class Child2 extends React.Component { handleClick = () => { // 直接使用props中的最新值计算 const newVal = this.props.outerMsg + 3; this.props.getMsg(newVal); }; render() { return <button onClick={this.handleClick}>to father</button>; } }
方式二:子组件监听props变化,同步更新自身状态
如果子组件必须维护自身状态,需要通过componentDidUpdate生命周期钩子监听props.outerMsg的变化,同步更新msgFromFather:
class Child2 extends React.Component { constructor(props) { super(props); this.state = { msgFromFather: props.outerMsg, }; } // 监听props变化,同步更新子组件状态 componentDidUpdate(prevProps) { if (prevProps.outerMsg !== this.props.outerMsg) { this.setState({ msgFromFather: this.props.outerMsg }); } } handleClick = () => { this.setState( { msgFromFather: this.state.msgFromFather + 3, }, () => { this.props.getMsg(this.state.msgFromFather); } ); }; render() { return <button onClick={this.handleClick}>to father</button>; } }
修改后,每次父组件传递新值,子组件都会同步更新,点击按钮时就能基于最新数值计算,实现每次点击增加103的预期效果。
内容的提问来源于stack exchange,提问作者Lei Sun
相关产品推荐
相关产品推荐

