简体   繁体   中英

React error: from controlled to uncontrolled component

EDIT: this question was marked as a duplicate by some users. Not sure if they read it before doing so. If someone did, please clarify in which sense this is a duplicate.

I have a component for checkboxes:

class Checkbox extends Component {
    onChange = (e) => {
        if (this.props.input) {
            this.props.input.onChange(e.target.checked);
        } else if (this.props.onChange) {
            this.props.onChange(e.target.checked, this.props.id);
        }
    };

    render() {
        const { input, value, className, label } = this.props;
        let inputValue = (input && input.value) || value;

        return (
            <div className={'Checkbox' + (className ? ' Checkbox--' + className : '')}>
                <input
                    className="Checkbox-input"
                    type="checkbox"
                    onChange={this.onChange}
                    checked={inputValue}
                />
                <span className="Checkbox-helper" />
                <span className="Checkbox-label" htmlFor="">
                    {label}
                </span>
            </div>
        );
    }
}

This component returns an error when the value changes.

Warning: A component is changing an uncontrolled input of type checkbox to be controlled. Input elements should not switch from uncontrolled to controlled (or vice versa). Decide between using a controlled or uncontrolled input element for the lifetime of the component.

But if I replace:

let inputValue = (input && input.value) || value;

with

let inputValue = value;
if (input) {
    inputValue = input.value;
}

Like so:

class Checkbox extends Component {
    onChange = (e) => {
        if (this.props.input) {
            this.props.input.onChange(e.target.checked);
        } else if (this.props.onChange) {
            this.props.onChange(e.target.checked, this.props.id);
        }
    };

    render() {
        const { input, value, className, label } = this.props;

        let inputValue = value;
        if (input) {
            inputValue = input.value;
        }

        return (
            <div className={'Checkbox' + (className ? ' Checkbox--' + className : '')}>
                <input
                    className="Checkbox-input"
                    type="checkbox"
                    onChange={this.onChange}
                    checked={inputValue}
                />
                <span className="Checkbox-helper" />
                <span className="Checkbox-label" htmlFor="">
                    {label}
                </span>
            </div>
        );
    }
}

It doesn't return any error. Why?

One possibility—there's not enough information here to say for sure—is that input.value is present but false (or falsy), so you fall back to the value prop, which is undefined , and you end up setting checked to undefined on your input.

This results in an uncontrolled checkbox.

Then, on a subsequent pass, either input.value or props.value has changed and you set checked to a real value, which means it's now a controlled input and react emits the warning.

In your initial case you'll get the value prop even if input.value is explicitly false or 0 or an empty string:

// if input.value === false here you get
// the fallback value which may be undefined
let inputValue = (input && input.value) || value;

In your modified case…

let inputValue = value;
if (input) {
  inputValue = input.value;
}

…you've avoided that scenario because you're predicating it on the presence of input itself rather than input.value .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM