0

I'm currently trying to implement a dynamic + multi-step form and was wondering how to update values of a map within a map.

For example: I have three fields "First Name", "Last Name", "Email". The name values I want to store within a key called "General" while the email value I would like to store within a key called "Contact". Currently, I have implemented a method called onChange that is given to each field and listens for changes and stores the field and its value within the state.

function App() {
  const [state, setState] = useState(false);

  const onChange = (field, value) => {
    console.log("Values:", value);

    setState({
      ...state,
      [field]: value
    });

    console.log("State:", state);
  };

  return (
    <div className="App">
      <EuiForm>
        <EuiFormRow label="First Name">
          <EuiFieldText
            name="first"
            onChange={event => onChange("firstName", event.target.value)}
          />
        </EuiFormRow>
        <EuiSpacer />

        <EuiFormRow label="Last Name">
          <EuiFieldText
            name="last"
            onChange={event => onChange("lastName", event.target.value)}
          />
        </EuiFormRow>
        <EuiSpacer />

        <EuiFormRow label="Email">
          <EuiFieldText
            name="email"
            onChange={event => onChange("email", event.target.value)}
          />
        </EuiFormRow>
        <EuiSpacer />

        <EuiButton type="submit" fill>
          Save form
        </EuiButton>
      </EuiForm>
    </div>
  );
}

What is the correct way of updating values so that the data in my state looks like this?

{
  "general": {
    "firstName": "ABCD",
    "lastName": "EFGH"
  },
  "contact": {
    "email": "[email protected]"
  }
}
1
  • have a look at my answer Commented Nov 16, 2019 at 9:43

2 Answers 2

1

To simplify, you can define two different states and then merge them upon submit. Here is an example:

function App() {
  const [general, setGeneral] = React.useState({});
  const [contact, setContact] = React.useState({});
  
  const onChange = (set, field, value) => {
    set(state => ({
      ...state,
      [field]: value
    }));
  };
  
  const onSubmit = (e) => {
    e.preventDefault();
    console.log({
      general,
      contact
    });
  }
  
  return (
    <div className="App">
      <form onSubmit={onSubmit}>
        <label htmlFor="First Name">First Name
          <input
            name="first"
            onChange={event => onChange(setGeneral, "firstName", event.target.value)}
          />
        </label>
        <hr />

        <label htmlFor="Last Name">Last Name
          <input
            name="last"
            onChange={event => onChange(setGeneral, "lastName", event.target.value)}
          />
        </label>
        <hr />

        <label htmlFor="Email">Email
          <input
            name="email"
            onChange={event => onChange(setContact, "email", event.target.value)}
          />
        </label>
        <hr />

        <button type="submit">
          Save form
        </button>
      </form>
    </div>
  );
}

ReactDOM.render(<App />, document.getElementById('root'));
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root"></div>

Sign up to request clarification or add additional context in comments.

2 Comments

thank you, this method is a cleaner way than what I originally intended.
How to update a nested array of objects on specific condition? e.g i had to update a nested(any level) proper when a condition meet
1

Initially take the state as an object , like this

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

than do some thing like this

const onChange = (field, value) => {
    var temp = {...state}
   if(field == 'firstName'){
      temp.general.firstName = value
      setState({
      ...state,
      general:temp
    });
   } else if(field == 'lastName'){
      temp.general.lastName= value
      setState({
      ...state,
      general:temp
    });
   } else if(field == 'email'){
      temp.contact.email= value
      setState({
      ...state,
      contact:temp
    });
   }

    console.log("State:", state);// this will not work as the setState is asynchronous


};


  // so you can view the state like this 
 useEffect(() => {
     console.log('State', state);  // so this block of code will watch for any changes in state
  }, [state]);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.