0

Hello I have a very complex form with many nested objects and I am wondering how to update a field in the nested objects without writing one million lines of code, this is what I currently have. I have heard about the library called immer but know nothing about it.

this is the initial value of the object

const initialFormState = {
  name: "",
  address: {
    street1: "",
    street2: "",
    city: "",
    state: "",
    zip: "",
    country: "",
    gps: {
      lat: "",
      lng: ""
    }
  },
  clientId: "",
  contact: {
    userId: "",
    firstName: "",
    lastName: "",
    jobTitle: ""
  },
  isActive: true,
  requiresAction: true,
  details: {
    lastInspectionDate: "",
    lastMaintenanceDate: "",
    employeesTrained: 0,
    phone: "",
    companyManager: {
      name: "",
      title: "",
      phone: "",
      email: ""
    },
    companyOwner: {
      name: "",
      title: "",
      phone: "",
      email: ""
    },
    companyContact: {
      name: "",
      title: "",
      phone: "",
      email: ""
    },
    companyType: "",
    locations: 0,
    foo: 0,
    bar: 0,
    foo2: "" 
  }
}

and my reducer function and state variables

const [formState, dispatch] = useReducer(formReducer, initialFormState)

const formReducer = (prevState: any, action: any) => {
  switch (action.type) {
    case 'update-name':
      return { ...prevState, name: action.payload}
      console.log()
      break
    case 'update-address':
      return { ...prevState, address: { ...prevState.address, [action.field]: action.payload}}
      break
    case 'update-contact':
      return { ...prevState, contact: { ...prevState.contact, [action.field]: action.paylod}}
      break
    case 'update-client-id':
      return { ...prevState, clientId: action.payload}
      break
    case 'update-isActive':
      return { ...prevState, isActive: action.payload }
      break
    case 'update-requiresAction':
      return { ...prevState, requiresAction: action.payload}
      break
    case 'update-details':
      return { ...prevState, details: { ...prevState.details, [action.field]: action.payload}}
  } 
}

but everytime I go to update the contact object, I keep getting undefined. This is what I am passing in the onChange for the text fields, I will use street line 1 as an example

onChange={(e) => { dispatch({ type: 'update-contact', field: 'street1', payload: e.target.value })}}
  • "I keep getting undefined" what _exactly_ is the error message? – Alex Wayne Jul 27 '22 at 22:36
  • What's the reason of keeping form data in redux store? Looks like you are trying to invent ReduxForm or some kind of bicycle. There are several form libraries like Formik, FinalForm and others. These solutions will easily handle complex objects, provide validations and much more. However if you need to place you data to redux you can do it onSubmit event. – lazy.lizard Jul 27 '22 at 22:44
  • its not redux it is just React's useReducer hook and I can't wrap it all with Formik because it is a modal that pops up when the user clicks on a button and each modal screen has some text fields or check boxes, it is about 5 modal screens in all or I would easily wrap it in a formik wrapper, I mean I could break the state up individually but that looks so ugly and is alot of code – Ryan Speciale Jul 27 '22 at 23:17
  • @Alex Wayne it is not throwing an error, I have it logging the value of formState whenever they switch to the next modal screen and it is coming up as undefined – Ryan Speciale Jul 27 '22 at 23:20
  • I decided not to use the reducer guys, I just put the entire object in a use state and updated everything with the spread syntax, it's alot of code but it works – Ryan Speciale Jul 28 '22 at 12:16
  • 1
    @RyanSpeciale Formik does support field names like `address.gps.lang`. You won't even need a local state, you'll be able to use `values` object from Formik context and your object as initial values for form. For example `` will solve your problem. Further, there's not problem to wrap all your components including modal with `useFormikContext` and show parts of your form in modal, providing `onChangeHandler` and `onBlurHandler` for your [custom] inputs in necessary. – lazy.lizard Jul 28 '22 at 12:25
  • Up to you. But this is redundant code and expensive action. – lazy.lizard Jul 28 '22 at 13:10
  • yeah your right, I should have just went with Formik, I just have never used it – Ryan Speciale Jul 29 '22 at 17:18
  • Related: https://stackoverflow.com/questions/47912522/update-nested-object-in-redux-reducer and https://stackoverflow.com/questions/40096036/how-to-update-a-value-of-a-nested-object-in-a-reducer – hb20007 Oct 20 '22 at 14:32

0 Answers0