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