Home > Blockchain >  suppress warning "Warning: You provided a `value` prop to a form field without an `onChange` ha
suppress warning "Warning: You provided a `value` prop to a form field without an `onChange` ha

Time:11-19

I have a warning that says

Warning: You provided a `value` prop to a form field without an `onChange` handler.

This will render a read-only field. If the field should be mutable use `defaultValue`.
`Otherwise, set either `onChange` or `readOnly`.`

Of course, I have googled a solution for it. One way to fix it is to replace "value" attribute with "defaultValues". But, this is causing another issue because my component is a controlled.

I could add onchange attribute and method to the fields. But the problem is that it will cause redundancy as I have a single onChange method on the tag that manages all the values and states. For example,

const [allStates, setAllStates] = useState({value_one: "", value_two:""});
function handleOnChange(event){
 .........
 //update the allStates state here
}

<Form onChange={handleOnChange}>
  <input value={allStates.value_one} />
  <input value={allStates.value_two} />
</Form>

What are the alternatives I have? Should I just ignore it since I can only see it on dev environments, the end users cannot and won't see it on the prod environment anyway?

CodePudding user response:

The warning it is giving you is that you have provided the input with a value argument, so when you go to type in the input, it won't work:

const [allStates, setAllStates] = useState({
  value_one: 'I will be display in the input initially', // <-- This text will already be entered in the text input.
  value_two: ''
});

<input value={allStates.value_one} />

But since you added the value prop, you need to give it an onChange, otherwise the value of the field will always be the same and you won't be able to change it.

Ofcourse you can add the onChange like this:

const [allStates, setAllStates] = useState({
  value_one: '',
  value_two: ''
});

const handleOnChange = (event) => {
  setAllStates({
    ...allStates,
    // Now you can target the name prop
    [event.target.name]: event.target.value
  });
}

return (
  <>
    {/* I will suggest adding a name prop also */}
    <input name="value_one" value={allStates.value_one} onChange={handleOnChange} />
    <input name="value_two" value={allStates.value_two} onChange={handleOnChange} />
  </>
);

The name prop is really useful for these one function setups, as it allows you to target the state value straight from the name.

But remember that the name values should be the same as the values in the state.

CodePudding user response:

It is a Helpful Warning by React, you can probably refer to this thread which discusses this.

https://github.com/facebook/react/issues/1118

Although adding the defaultValue should work for you, since your state has the latest value for the inputs, and when your component would render for the first time as long as the defaultValue is assigned to your <input>, the fields would reflect your state.

const [state, setState] = useState({});

const handleChange = (ev) => {
  setState(prev_state => {
    return {
      ...prev_state,
      [ev.target.name]: ev.target.value
    }
  })
}

<form onChange={handleChange}>
  <input name={"foo"} defaultValue={state.foo}/>
  <input name={"bar"} defaultValue={state.bar}/>
</form>

  • Related