0
votes

I'm making a little blog in React and I have a problem updating the state on input change event.

The warning is:

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

This is my code:

Constructor:

constructor(props){
        super(props);

        this.state = {
            id: '',
            post: {
                title: '',
                slug: '',
                content: ''
            }
        }

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

    }

handleChange function

handleChange(event) {
        const target = event.target;
        const value = target.type === 'checkbox' ? target.checked : target.value;
        const name = target.name;

        this.setState({
            post: {
                [name]: value
            }
        });
    }

input render:

render(){
        return (
            <div>
                <AdminMenu />
                <div id="admin-post-form">
                    <div className="input-group vertical">
                        <label>Título</label>
                        <input
                            name="title"
                            placeholder="Título"
                            type="text"
                            value={this.state.post.title}
                            onChange={this.handleChange}
                        />
                    </div>
                    <div className="input-group vertical">
                        <label>Slug</label>
                        <input
                            name="slug"
                            placeholder="Slug"
                            type="text"
                            value={this.state.post.slug}
                            onChange={this.handleChange}
                        />
                    </div>

                </div>
            </div>
        )
    }

What's wrong with my code ? The field is updated, but I get that warning.

Thanks!

3

3 Answers

9
votes

This:

    this.setState({
        post: {
            [name]: value
        }
    });

will replace this.state.post completely with an object that only has a single key. For example, if name is slug, you will replace post with { slug: 'something' }.

As a result, if you edit one field, all other fields will become undefined. React treats value={undefined} as an uncontrolled component and warns you.

To fix the issue, you probably want to merge post updates with the existing object instead of replacing it:

    this.setState(prevState => ({
        post: {
            ...prevState.post,
            [name]: value
        }
    }));
1
votes

Your set state is resetting the whole post object. You likely want to do something like:

this.setState({
    post: {
        ...this.state.post
        [name]: value
    }
})
0
votes

Solved using spread operator, this is the updated handleChange function that works with nested property:

handleChange(event) {
        const target = event.target;
        const value = target.type === 'checkbox' ? target.checked : target.value;
        const name = target.name;

        var post = {...this.state.post}
        post[name] = value;
        this.setState({post});
    }