0

im currently trying to create an dynamic form that uses a sub component to render out some input fields as createing them static would exceed a limit. I pass the states for the the form i made aswell as some date and the change form. But when i render the form as it does so fine! as soon as i change the state its sends a warning about uncontrolled components that you can read about it here

I have tried pre-setting all the fields with empty defaults but it doesnt help.

Am i doing it somewhat correct or totally wrong? or what is the correct way, or what am i doing wrong. thanks in adbance.

As for the code looks like this:

Edit.js

export default function InventoryItemEdit() {
  const [form, setForm] = useState({});

  function handleFormChange(e) {
    setForm({ ...form, [e.target.name]: e.target.value });
  }

  const variants = (
    <ItemVariants
      form={form}
      onChange={handleFormChange}
      fields={form.sizes} 
      /* ^^ fields data fetched from the server i set via use effect hook when loading the page */
    />
  );

  const updateItem = async (event) => {
    event.preventDefault();
    /* Do form submit post */
  };

  return (
    <form onSubmit={updateItem}>
      <div>
        <p htmlFor="name">Name</p>
        <input
          id="name"
          name="name"
          onChange={handleFormChange}
          value={form.name}
          type="text"
          required
          placeholder="Name of Item"
        />
      </div>
      {variants}
    </form>
  );
}

As for the sub component ItemVariants it looke like this

ItemVariants.js

export default function ItemVariants({
  form = {},
  onChange = '',
  fields = [],
}) {
  return (
    <>
      {fields.map((row, index) => (
         <div>
           <span>
             {row.name}
           </span>
           <input
             type="text"
             id={`variant${index}`}
             name={`variant${index}`}
             onChange={onChange}
             value={form[`variant${index}`]}
             required
             min="0"
             placeholder="0"
             defaultValue="0"
           />
         </div>
      ))}
    </>
  );
}
Melonendk
  • 107
  • 1
  • 10
  • Both the name input and the variant inputs values need to default to empty string, i.e. `value={form.name ?? ''}` and ``value={form[`variant${index}`] ?? ''}``. You get the error because those values are initialized as `undefined` and then changed to a value. – juliomalves Nov 05 '21 at 18:21
  • Does this answer your question? [React - changing an uncontrolled input](https://stackoverflow.com/questions/37427508/react-changing-an-uncontrolled-input) – juliomalves Nov 05 '21 at 18:24

2 Answers2

0
  1. Controlled component: is when your input value is coming from a single source of truth a state(meaning for an input value to change, you need to update the state holding the value)
  2. Uncontrolled component: is when your input value is not coming from a state but rather it's coming from something we call useRef/createRef which helps to reference to react syntactic DOMNODE thus giving us the ability to interact with input in a false-actual-DOM(as if we were query an actual DOM input-node in pure-JS). Meaning if your input value is not coming from a state, it must come from a ref(ref.current.value which is equivalent to document.querySelector(theInputLocator).value).

Answer to your bug: I see that everything is okay, but the only issue is that you didn't set the initial state with the name key. Thats an analysing issue because in your code you doing [e.target.name]:e.target.value and the way inputs works generally is that event is triggered but must recent value is emitted when the event happens next. it works like a++.

Do this:

 const [form, setForm] = React.useState({ name: '' });

The general rule of thumb is that always describe your form input keys when your inputs are predefine and not dynamic(in this case your name input is predefined).

Emmanuel Onah
  • 580
  • 4
  • 8
  • thanks for the explanation, but i already tried setting the initial state, but and the main inputs (name for example) works fine gives no explanation, but as soon it's the sub component inputs it doesn't work, and gives a warning even tho i have tried initial state for them to. And haven't still the same – Melonendk Nov 04 '21 at 10:47
  • I just got an idea i could set an internal function and state that change values but also sets the form data. Might not be the best solution as it's basically double data which is not the best – Melonendk Nov 04 '21 at 10:49
0

So After digging reading this post i have to thank! @juliomalves for solution with value={form[`variant${index}`] ?? ''} or value={form[`variant${index}`] || ''}

I also found out i was accidently adding defaultvalue aswell as value which cannot be set at the same time i found out. After i tested it removed the default value and set it correctly to be a string! it now works like a charm! Also thanks to @Emmanuel Onah for the explaination it really helped me understand more about the react states!

Thanks again for everyone that helped

Melonendk
  • 107
  • 1
  • 10