Display multiple dynamic input fields in react, based on a changing state variable?

Viewed 588

So, I am building my first React app, that connects to a Flask backend. I have a specific functional component that fetches a dictionary from the Python program, and I have saved this in a state variable(done using useState, setVariables). The object is of type

{'A':'x', 'B':'y', 'C':2},

and these are variable, and each render needs to be dynamic, based only on this object. Based on the current state of this object, I want to display key-value pairs of this object in

<label>insertkey</label>
<input type="text" name = "insertkey" value=insertvalue/>

In addition, I want to be able to save any changes made to these values, and write into the state variable, so that I can send them back to my Flask backend.

I tried looping through each, and inserting as follows:

const [fields, setFields] = useState({});
//intermediate code for fetching and setting the state 

useEffect(() => {
  for (const [key, value] of Object.entries(fields)) {
    console.log(`${key}:${value}`);
    insert = insert + `<label> ${key} </label> <input type = 'text' value = ${value} name = ${key} onChange=${changedData()}></input><br/>`
  }

  document.getElementById('fields_form').innerHTML = insert;
});
const changedData = (evt) => {
  setFields({ [evt.target.name]: evt.target.value });
  console.log(evt.target.value);
}

//some intermediate code

return (
  <div>
    <form onSubmit={submitFunction}>
      <p id='fields_form'>

      </p>
      <input type="submit" value="Submit"></input>
    </form>
  </div>
);

But when I do this, the state is set as 'Undefined'.

I would love to hear about some ways to implement this. Maybe it's a really small fix, and I'm missing it, or perhaps there is a different approach that could be more suitable.

1 Answers

Simple:

const Form = () => {
  const [values, setValues] = useState({});
  const onChange = (e) => {
    const name = e.target.name;
    let value = e.target.value;
    setValues({ ...values, [name]: value });
  };
  const onSubmit = (e) => {
    // send data or save it to local store
    api.send(values)
  };
  return (
    <form encType="multipart/form-data">
      <input
        type="text"
        name="email"
        value={value["email"]}
        onChange={onChange}
      />
      <input
        type="text"
        name="subject"
        value={value["subject"]}
        onChange={onChange}
      />
      <input
        type="text"
        name="body"
        value={value["body"]}
        onChange={onChange}
      />
      >
      <button type="submit" onClick={onSubmit}>
        Save
      </button>
    </form>
  );
};

export default Form;
console.log(values);

It's your solution.

const [fields, setFields] = useState({});
const [values, setValues] = useState({});

// some fetch logic

// happens on loading some data
// for example data structure look's like:
// fetchedData = {
//   email: 'email@placeholder'
//   subject: 'subject placeholder'
//   body: 'body placeholder'
// }
useEffect(() => {
  if (fetchedData) {
    setFields(fetchedData)
  }
}, [fetchedData]);

// happens on fields changed
useEffect(() => {
  if (fields) {
    setValues(fields)
  }
}, [fields]);


const changedData = (evt) => {
  setValues({ ...values, [evt.target.name]: evt.target.value });
}

return (
  <div>
    <form onSubmit={submitFunction}>
      {Object.keys(fields).map(_ => (
        <input
          type="text"
          name={_}
          value={values[_]}
          onChange={changedData}
        />
      ))}
      <input type="submit" value="Submit"></input>
    </form>
  </div>
);
Related