reactjsreact-hooksonchangeuse-statecontrolled-component

Warning: A component is changing a controlled input of type undefined to be uncontrolled


I got the following warning when using controlled components, despite having set the initial states: Warning: A component is changing a controlled input of type undefined 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.

Here is my code:

import React, { useState } from "react";

function App() {
    const [fullName, setFullName] = useState({
        fName: "",
        lName: ""
    });

    function handleChange(event) {
        const { value, name } = event.target;

        setFullName(prevValue => {
            if (name === "fName") {
                return {
                    fName: value,
                    lName: prevValue.lName
                };
            } else if (name === "lName") {
                return {
                    fName: prevValue.fName,
                    lname: value
                };
            }
        });
    }

    return (
        <div className="container">
            <h1>
                Hello {fullName.fName} {fullName.lName}
            </h1>
            <form>
                <input
                    name="fName"
                    onChange={handleChange}
                    placeholder="First Name"
                    value={fullName.fName}
                />
                <input
                    name="lName"
                    onChange={handleChange}
                    placeholder="Last Name"
                    value={fullName.lName}
                />
                <button>Submit</button>
            </form>
        </div>
    );
}

export default App;

If I type John as the fName and Doe as the lName in the inputs, the headline should be Hello John Doe, but I just got Hello John with the warning. Using the condition below will get rid of the warning, but I just get Hello John again:

value={fullName.lName || ""}

How to get both fName and lName displayed at the same time without the warning?


Solution

  • This is happening because of a typo. Change :

    else if (name === "lName") {
       return {
          fName: prevValue.fName,
          lname: value
       };
    }
    

    to:

    else if (name === "lName") {
       return {
          fName: prevValue.fName,
          lName: value // notice 'n' was in lowercase.
       };
    }
    

    Also, a more concise way to go about it (in my opinion) would be:

    setFullName((prevValue) => ({
        ...prevValue, [name] : value
    }));
    

    Working example : here