How to disable button in React.js

Question

I have this component:

import React from 'react';

export default class AddItem extends React.Component {

add() {
    this.props.onButtonClick(this.input.value);
    this.input.value = '';
}


render() {
    return (
        <div className="add-item">
            <input type="text" className="add-item__input" ref={(input) => this.input = input} placeholder={this.props.placeholder} />
            <button disabled={!this.input.value} className="add-item__button" onClick={this.add.bind(this)}>Add</button>
        </div>
    );
}

}

I want the button to be disabled when input value is empty. But the code above doesn't work. It says:

add-item.component.js:78 Uncaught TypeError: Cannot read property 'value' of undefined

pointing to disabled={!this.input.value}. What can I be doing wrong here? I'm guessing that perhaps ref isn't created yet when render method is executed. If, so what is the workararound?


Show source
| javascript   | reactjs   2017-01-05 16:01 3 Answers

Answers to How to disable button in React.js ( 3 )

  1. 2017-01-05 16:01

    You shouldn't be setting the value of the input through refs.

    Take a look at the documentation for controlled form components here - https://facebook.github.io/react/docs/forms.html#controlled-components

    In a nutshell

    <input value={this.state.value} onChange={(e) => this.setState({value: e.target.value})} />
    

    Then you will be able to control the disabled state by using disabled={!this.state.value}

  2. 2017-01-05 16:01

    this.input is undefined until the ref callback is called. Try setting this.input to some initial value in your constructor.

    From the React docs on refs, emphasis mine:

    the callback will be executed immediately after the component is mounted or unmounted

  3. 2017-01-05 16:01

    Using refs is not best practice because it reads the DOM directly, so use React's state instead.

    Your button doesn't change because the component is not re-rendered and stays in its initial state. You can use React's setState together with an onChange event listener to render the component again every time the input field changes:

    class AddItem extends React.Component {
      constructor() {
        super();
        this.state = { value: '' };
        this.onChange = this.onChange.bind(this);
        this.add = this.add.bind(this);
      }
    
      add() {
        this.props.onButtonClick(this.state.value);
        this.setState({value: ''});
      }
    
      onChange(e) {
        this.setState({value: e.target.value});
      }
    
      render() {
        return (
          <div className="add-item">
            <input type="text" className="add-item__input" value={this.state.value} onChange={this.onChange} placeholder={this.props.placeholder} />
            <button disabled={!this.state.value} className="add-item__button" onClick={this.add}>Add</button>
          </div>
        );
      }
    }
    
    ReactDOM.render(<AddItem placeholder="Value" onButtonClick={v => console.log(v)} />, document.getElementById('View'));
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
    <div id='View'></div>

Leave a reply to - How to disable button in React.js

◀ Go back