I'm a javascript lover but I'm a fresh React beginner. I've got some trouble understanding the React logic so I've made a simple example, an app with a numeric input and a cancel button that cancels last action:
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">
<input type="number" value={this.state.selectedNumber} onChange={this.onNumberChange}></input>
<button disabled={this.state.lastNumber===null} onClick={this.onUndo}>Undo last action</button>
</div>
);
}
onNumberChange=(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});
}
}
ReactDOM.render(<App/>, document.getElementById('root'));
<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-dom/16.6.3/umd/react-dom.production.min.js"></script>
</body>
</html>
Everything works fine but let's say the user enters the number 200 (by typing), and then want to undo this value and retrieve the last one, it will fallback to 20 because each keyboard entry refresh the state with the input value...
To avoid this behaviour I tried to move the input into a custom component, add local state to it and renders the input value according to the component props. I added a onChange event locally that set the component state accordingly to user "live" typing, and I binded a onBlur event to the parent's callback that sets its own state accordingly to "complete" user entry.
The component renders well initially, renders well when you type in it, but doesn't update when changed externally by the cancel button...
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
}
}
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>
<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-dom/16.6.3/umd/react-dom.production.min.js"></script>
</body>
</html>