'React useReducer: How to have a dispatch function update a object nested in initial state object

Consider the following:

I have an initial state object:

const INITIAL_STATE = {
  visited: false,
  isSaveAllowed: false,
  isWithdrawAllowed: false,
  isContinuationAllowed: false
}

Which is being copied/spread to a collection of objects; I want each of those objects in viewDataInitialState to have those properties from INITIAL_STATE:

const viewDataInitialState = {
  detailsViewData: { ...INITIAL_STATE },
  discountsViewData: { ...INITIAL_STATE },
  documentsViewData: { ...INITIAL_STATE },
  fieldRepViewData: { ...INITIAL_STATE }
}

This is my reducer:

 function viewDataReducer (state, { type, payload }) {

    function makeFieldUpdater (payload) {
      return function (payload = {}) {
        return { ...state, ...{ isSaveAllowed: payload.isSaveAllowed } }
      }
    }

  switch (type) {
    case 'MAKE_FIELD_UPDATER': {
     makeFieldUpdater(payload)
    }
        default: 
        return state
   }

function ViewDataProvider ({ children }) {
    const [state, dispatch] = React.useReducer(viewDataReducer, viewDataInitialState)
    
    function updateDetailsViewData(kindOfData) {
        dispatch({
          type: 'UPDATE_DETAILS_VIEW_DATA',
          payload: kindOfData
        })
     }

  return (
    <ViewDataStateContext.Provider value={{ state }}>
      <ViewDataDispatch.Provider 
        value={{ 
          updateDetailsViewData, 
        }}
      >
        {children}
      </ViewDataDispatch.Provider>
    </ViewDataStateContext.Provider>
  )
}

How could I get updateDetailsViewData to update the correct state object?

Example, I use the dispatcher in a child, but I want it to update fieldRepViewData for instance?

function Child(){
   const { updateDetailsViewData } = viewDataDispatch()
   // later
   updateDetailsViewData({ isAllowed: true}) // please sir update only fieldRepViewData
}

In another implementation of this we were passing the setState function to makeFieldUpdater

function makeFieldUpdater (setStateFn) {
  /**
   * Pass an object. Immer will replace state props as needed
   * @param {Object} payload
   */
  return function (payload = {}) {
    setStateFn(
      produce((draft) => Object.assign(draft, payload))
    )
  }
}

function useViewData () {
  const [detailsViewData, setDetailsViewData] = useState({ ...INITIAL_STATE })
  const [discountsViewData, setDiscountsViewData] = useState({ ...INITIAL_STATE })
  const [documentsViewData, setDocumentsViewData] = useState({ ...INITIAL_STATE })
  const [fieldRepViewData, setFieldRepViewData] = useState({ ...INITIAL_STATE })

  return {
    detailsViewData,
    updateDetailsViewData: makeFieldUpdater(setDetailsViewData),
    resetDetailsViewData: makeFieldResetter(setDetailsViewData),

    discountsViewData,
    updateDiscountsViewData: makeFieldUpdater(setDiscountsViewData),
    resetDiscountsViewData: makeFieldResetter(setDiscountsViewData),

    documentsViewData,
    updateDocumentsViewData: makeFieldUpdater(setDocumentsViewData),
    resetDocumentsViewData: makeFieldResetter(setDocumentsViewData),

    fieldRepViewData,
    updateFieldRepViewData: makeFieldUpdater(setFieldRepViewData),
    resetFieldRepViewData: makeFieldResetter(setFieldRepViewData)
  }
}

Basically I'd like an agnostic dispatcher?



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source