React Functional components Form handling with object in state

Viewed 6391

So im trying to create a form with functional components in React. I have a state which contains an object

const [event, setEvent] = useState(props.location.event);
{
    "id": 1,
    "limit": 2000,
    "price": 10,
    "accessLvl": 0,
    "details": "Event that contains all the fields",
    "duration": 24,
    "eventType": 1,
    "eventLocation": "asdasd",
    "creator": 1,
    "startDate": "2020-06-01T12:00:00",
    "title": "Testing update",
    "imageUrl": "d0659c5e-7ca1-4b02-b148-6221d6e7d7a8"
}

It is a edit form so i have the input values set to these variables. With class component i could do it easily but with functional component when i try to change one variable for example title and the object is only going to contain the title which is not the behavior that i want.

<input type="text" className="form-control" value={props.event.title} onChange={e => props.onTodoChange(e.target.value, "title")} id="EventTitle" />

  function onTodoChange(value, key) {
    setEvent({[key] : value})
  }
4 Answers

Will this work?

function onTodoChange(value, key) {
  setEvent(ev => ({
    ...ev,
    [key] : value,
  }))
}

The function setEvent can take a function with one argument that is the previous event. The ...ev copies all of ev's properties into the new object, then you overwrite the needed property with [key] : value.

    setEvent({...event, [name of varible]: value})
ex: setEvent({...event, title:'Hi'})

This is the way to update object using hooks.

Unlike the setState method found in class components, useState does not automatically merge update objects. You can replicate this behavior by combining the function updater form with object spread syntax:

setState(prevState => { // Object.assign would also work
  return {...prevState, ...updatedValues};
});

Another option is useReducer, which is more suited for managing state objects that contain multiple sub-values.

Doc link

/**
 * 
 *   USAGE: 
 *  1. const [profile, setProfile] = useState(null);
 *   
 *  2. const setsProperty = formObjectMutator(setProfile, () => validationErrors && setValidationErrors(null));
 *   
 *  3. <input type="text" onChange={setsProperty('firstName')} />
 * 
 * @param  {function}  clearMessagesFn  Clears validation messages once the user starts typing (optional).
 * @param   {function} setValueFn       The function that is used to modify the state object
 * @returns {function} A fuction that takes a propertry name and returns a function that handles change events for that property
 */
export  const formObjectMutator = (mutateStateFn, clearMessagesFn) => property => event => {
        // This line is necessary, do not access the event object from the function passed to the 
        // mutator function or you will cause a bug.
        const newValue = event.target.value;

        mutateStateFn(prevState => { return { ...prevState, [property]: newValue} } );

        if(clearMessagesFn)
            clearMessagesFn();
}
Related