React输入框撤销功能异常与自定义组件外部更新失效问题求助
解决React自定义组件未同步父组件状态的问题
嘿,我懂你碰到的麻烦了——你的自定义MyNumericInput组件用本地state处理实时输入、失焦再同步父组件状态的思路没问题,但当你点击撤销按钮让父组件更新selectedNumber时,子组件的输入框却没跟着变,对吧?
问题根源
你的子组件MyNumericInput的本地selectedNumber只在**组件初始化阶段(constructor里)**从props拿了一次值。之后父组件的props变化时,React不会自动更新子组件的本地state,所以子组件根本不知道父组件的状态已经发生了改变。
解决方案:监听props变化同步本地state
我们可以在子组件里添加componentDidUpdate生命周期钩子,用来检测父组件传来的selectedNumber props是否发生变化,如果变了,就同步更新子组件的本地state。
修改后的MyNumericInput组件代码如下:
class MyNumericInput extends React.Component { constructor(props){ super(props); this.state={ selectedNumber:props.selectedNumber } } // 添加这个生命周期钩子,监听props变化 componentDidUpdate(prevProps) { // 对比前后props,若selectedNumber不同则更新本地state if (prevProps.selectedNumber !== this.props.selectedNumber) { this.setState({ selectedNumber: this.props.selectedNumber }); } } render() { return( <input type="number" value={this.state.selectedNumber} onChange={this.onChange} onBlur={this.props.onBlur}/>); } onChange=(e)=>{ this.setState({selectedNumber:e.target.value}); } }
为什么这样有效?
当你点击撤销按钮,父组件的selectedNumber状态更新后,会把新的props传给子组件。这时子组件的componentDidUpdate会被触发,它会对比之前的props和当前的props,发现selectedNumber不一样了,就调用setState更新自己的本地state,输入框也就会显示最新的数值了。
完整修改后代码
这里整合了整个应用的代码,你可以直接测试:
JSX部分
class App extends React.Component { //A simple numeric input and a cancel button constructor(props){ super(props); this.state={ selectedNumber:0, lastNumber:null } } render() { return ( <div className="App"> <MyNumericInput selectedNumber={this.state.selectedNumber} onBlur={this.onBlur}/> <button disabled={this.state.lastNumber===null} onClick={this.onUndo}>Undo last action</button> </div> ); } onBlur=(e)=>{ let prevNumber=this.state.selectedNumber; this.setState({selectedNumber:e.target.value, lastNumber:prevNumber}); } onUndo=(e)=>{ let prevNumber=this.state.lastNumber; this.setState({selectedNumber:prevNumber,lastNumber:null}); } } class MyNumericInput extends React.Component { constructor(props){ super(props); this.state={ selectedNumber:props.selectedNumber } } componentDidUpdate(prevProps) { if (prevProps.selectedNumber !== this.props.selectedNumber) { this.setState({ selectedNumber: this.props.selectedNumber }); } } render() { return( <input type="number" value={this.state.selectedNumber} onChange={this.onChange} onBlur={this.props.onBlur}/>); } onChange=(e)=>{ this.setState({selectedNumber:e.target.value}); } } ReactDOM.render(<App/>, document.getElementById('root'));
HTML部分
<html> <head> <meta charset="utf-8"> </head> <body> <div id="root"> </div> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react-dom.production.min.js"></script> </body> </html>
这样修改后,你输入200、失焦,再点击撤销按钮,输入框就会正确回退到之前的数值,不会再出现状态不同步的问题啦!
内容的提问来源于stack exchange,提问作者Kevin Castejon
相关产品推荐
相关产品推荐

