React - changing an uncontrolled input

2019-01-08 04:22发布

I have a simple react component with the form which I believe to have one controlled input:

import React from 'react';

export default class MyForm extends React.Component {
    constructor(props) {
        super(props);
        this.state = {}
    }

    render() {
        return (
            <form className="add-support-staff-form">
                <input name="name" type="text" value={this.state.name} onChange={this.onFieldChange('name').bind(this)}/>
            </form>
        )
    }

    onFieldChange(fieldName) {
        return function (event) {
            this.setState({[fieldName]: event.target.value});
        }
    }
}

export default MyForm;

When I run my application I get the following warning:

Warning: MyForm is changing an uncontrolled input of type text 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

I believe my input is controlled since it has a value. I am wondering what am I doing wrong?

I am using React 15.1.0

8条回答
Evening l夕情丶
2楼-- · 2019-01-08 04:50

If the props on your component was passed as a state, put a default value for your input tags

<input type="text" placeholder={object.property} value={object.property ? object.property : ""}>
查看更多
甜甜的少女心
3楼-- · 2019-01-08 04:51

When you first render your component, this.state.name isn't set, so it evaluates to undefined, and you end up passing value={undefined} to your input.

When ReactDOM checks to see if a field is controlled, it checks to see if value != null (note that it's !=, not !==), and since undefined == null in JavaScript, it decides that it's uncontrolled.

So, when onFieldChange() is called, this.state.name is set to a string value, your input goes from being uncontrolled to being controlled.

If you do this.state = {name: ''} in your constructor, because '' != null, your input will have a value the whole time, and that message will go away.

查看更多
The star\"
4楼-- · 2019-01-08 04:59

I know others have answered this already. But one of the very important factor here that may help other people experiencing similar issue:

You must need to have onChange handler added in your input field (e.g. textField, checkbox, radio, etc). And always handle activity through the onChange handler, like:

<input ... onChange={ this.myChangeHandler} ... />

and when you are working with checkbox then you may need to handle its checked state with !! like:

<input type="checkbox" checked={!!this.state.someValue} onChange={.....} >

Reference: https://github.com/facebook/react/issues/6779#issuecomment-326314716

查看更多
地球回转人心会变
5楼-- · 2019-01-08 04:59

When you use onChange={this.onFieldChange('name').bind(this)} in your input you must declare your state empty string as a value of property field.

incorrect way:

this.state ={
       fields: {},
       errors: {},
       disabled : false
    }

correct way:

this.state ={
       fields: {
         name:'',
         email: '',
         message: ''
       },
       errors: {},
       disabled : false
    }
查看更多
叛逆
6楼-- · 2019-01-08 05:02

I believe my input is controlled since it has a value.

For an input to be controlled, its value must correspond to that of a state variable.

That condition is not initially met in your example because this.state.name is not initially set. Therefore, the input is initially uncontrolled. Once the onChange handler is triggered for the first time, this.state.name gets set. At that point, the above condition is satisfied and the input is considered to be controlled. This transition from uncontrolled to controlled produces the error seen above.

By initializing this.state.name in the constructor:

e.g.

this.state = { name: '' };

the input will be controlled from the start, fixing the issue. See React Controlled Components for more examples.

Unrelated to this error, you should only have one default export. Your code above has two.

查看更多
Deceive 欺骗
7楼-- · 2019-01-08 05:04

Set a value to 'name' property in initial state.

this.state={ name:''};

查看更多
登录 后发表回答