I know some react but I am stuck in a weird situation.
I have two inputs and a button, the button should be enabled when both inputs are not empty. So, I used a state property for each input value and also one property telling me if both inputs have value:
this.state = {
title: '',
time :'',
enabled : false
}
also I have a onChange for each input to set State accordingly:
<input type="text" id="time" name="time" onChange={this.onChange.bind(this)} value={this.state.time}></input>
<input type="text" id="title" name="title" onChange={this.onChange.bind(this)} value={this.state.title}></input>
and the onChange is like this
onChange(e){
this.setState({
[e.target.id] : e.target.value,
enabled : ( (this.state.title==='' || this.state.time==='' ) ? false : true)
});
}
the problem is that the setState looks at previous state and the enabled is always one step behind, so if I type X in first and Y on second, still the enabled would be false.
I managed to solve it by using a setTimeout and taking the second line in it but it looks wrong to me.
onChange(e){
this.setState({
[e.target.id] : e.target.value,
});
setTimeout(() => {
this.setState({
enabled : ( (this.state.title==='' || this.state.time==='' ) ? false : true)
});
}, 0);
}
Any better solutions?
Any better solutions?
There are 3 solutions for you to achieve that, just pick one
componentDidUpdate()
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
title: "",
time: "",
enabled: false
};
}
onChange(e) {
this.setState({
[e.target.id]: e.target.value
});
}
componentDidUpdate(prevProps, prevState) {
if (
prevState.time !== this.state.time ||
prevState.title !== this.state.title
) {
if (this.state.title && this.state.time) {
this.setState({ enabled: true });
} else {
this.setState({ enabled: false });
}
}
}
render() {
return (
<React.Fragment>
<input
type="text"
id="time"
name="time"
onChange={this.onChange.bind(this)}
value={this.state.time}
/>
<input
type="text"
id="title"
name="title"
onChange={this.onChange.bind(this)}
value={this.state.title}
/>
<button disabled={!this.state.enabled}>Button</button>
</React.Fragment>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root"></div>
setState
callbackclass App extends React.Component {
constructor(props) {
super(props);
this.state = {
title: "",
time: "",
enabled: false
};
}
onChange(e) {
this.setState({[e.target.id]: e.target.value},
() => {
if (this.state.title && this.state.time) {
this.setState({ enabled: true });
} else {
this.setState({ enabled: false });
}
}
);
}
render() {
return (
<React.Fragment>
<input
type="text"
id="time"
name="time"
onChange={this.onChange.bind(this)}
value={this.state.time}
/>
<input
type="text"
id="title"
name="title"
onChange={this.onChange.bind(this)}
value={this.state.title}
/>
<button disabled={!this.state.enabled}>Button</button>
</React.Fragment>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root"></div>
enabled
based on title
and time
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
title: "",
time: ""
};
}
onChange(e) {
this.setState({
[e.target.id]: e.target.value
});
}
render() {
const enabled = this.state.time && this.state.title;
return (
<React.Fragment>
<input
type="text"
id="time"
name="time"
onChange={this.onChange.bind(this)}
value={this.state.time}
/>
<input
type="text"
id="title"
name="title"
onChange={this.onChange.bind(this)}
value={this.state.title}
/>
<button disabled={!enabled}>Button</button>
</React.Fragment>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root"></div>
First of all, you do not need to maintain a state for enabled, since it can be derived from other state values and can be directly done in render
onChange(e){
this.setState({
[e.target.id] : e.target.value,
});
}
render() {
const enabled = this.state.title !== "" && this.state.time !== "";
return (
<div>
<input type="text" id="time" name="time" onChange={this.onChange.bind(this)} value={this.state.time}></input>
<input type="text" id="title" name="title" onChange={this.onChange.bind(this)} value={this.state.title}></input>
<button disabled={!enabled}>Button</button>
</div>
)
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With