Form elements should be either controlled or uncontrolled

  • REACT_MISUSED_CONTROLLED_COMPONENT
  • Error
  • Medium
  • react

This rule applies when a form element such as <input>, <textarea>, and <select> works as both controlled and uncontrolled element.

The followings are controlled elements whose values are controlled by React state and associated handler functions:

  1. A form element has value prop
  2. <input> element of type radio or checkbox has checked prop

In contrast, the followings are uncontrolled elements with the initial values:

  1. A form element has defaultValue prop
  2. <input> element of type radio or checkbox has defaultChecked prop

Therefore, a form element should not have both value and defaultValue props. Also, <input> element should not have both checked and defaultChecked props. React outputs a warning message if you set both props for a form element.

Noncompliant Code Example

import React from 'react';
import ReactDOM from 'react-dom';

class FormExample extends React.Component {
    constructor(props) {
        super(props);
        this.state = {value: ''};

        this.handleChange = this.handleChange.bind(this);
        this.handleSubmit = this.handleSubmit.bind(this);
    }

    handleChange(event) {
        this.setState({value: event.target.value});
    }

    handleSubmit(event) {
        alert('The submitted value: ' + this.state.value);
        event.preventDefault();
    }

    render() {
        return (
            <form onSubmit={this.handleSubmit}>
                <label>
                    Name:
                    <input type="text" value={this.state.value} defaultValue="DeepScan" onChange={this.handleChange} /> {/* REACT_MISUSED_CONTROLLED_COMPONENT alarm because 'input' element should be either controlled or uncontrolled. */}
                </label>
                <input type="submit" value="Submit" />
            </form>
        );
    }
}
ReactDOM.render(<FormExample />, document.createElement('app'));

Compliant Code Example

import React from 'react';
import ReactDOM from 'react-dom';

class FormExample extends React.Component {
    constructor(props) {
        super(props);
        this.state = {value: 'DeepScan'};

        this.handleChange = this.handleChange.bind(this);
        this.handleSubmit = this.handleSubmit.bind(this);
    }

    handleChange(event) {
        this.setState({value: event.target.value});
    }

    handleSubmit(event) {
        alert('The submitted value: ' + this.state.value);
        event.preventDefault();
    }

    render() {
        return (
            <form onSubmit={this.handleSubmit}>
                <label>
                    Name:
                    <input type="text" value={this.state.value} onChange={this.handleChange} />
                </label>
                <input type="submit" value="Submit" />
            </form>
        );
    }
}
ReactDOM.render(<FormExample />, document.createElement('app'));

Version

This rule was introduced in DeepScan 1.8.0-beta.

See