si2030
si2030

Reputation: 4045

Redux Reducer - Array of objects being dispatched but not being saved to state

New to this.

I have an action that retrieves data from an ASP.NET Core API via a Fetch "GET". Its dispatched to the reducer. The reducer is called and at that point, while the object makes it there the state is not updated. So the action did deliver the payload. The reducer received the payload but he state was NOT updated. Why?

At the outset I am wondering if I have to accomodate for the fact they are arrays of objects.

There are Two array objects and a string value in the viewModel.

The structure of this viewModel is as follows:

AddressLocationDropdownViewModel = an int Id and four string values.

StateViewModel = an int Id and two string values.

CompanyStateShortName = A string.

Once it has retrieved the data I can look at the Redux tool in the F12 option on Chrome. State has been changed the action shows the payload but the payload has NOT updated the state even though its received.

Here is a detailed breakdown of each of the lists in the action as it was received and is displayed in the action tab on the redux tool..

Two pics showing The action payload with the breakdown of the payload object arrays.

enter image description here

enter image description here

Here is the initial state with the three items ringed.

Initial State

After it has run through and finished with the reducer, this is the finished state and those Items are now clearly missing.

enter image description here

Yet the action above indicates it received the data.

Here is the code for the action The second fetch only happens after the JWT has been received as it is saved into local storage via the call: "saveJwt(data)"

export const requestLoginToken = (username, password) =>
  (dispatch, getState) => {
    dispatch({ type: REQUEST_LOGIN_TOKEN, payload: username })

    const payload = {
      userName: username,
      password: password,
    }

    const task = fetch('/api/jwt', {
      method: 'POST',
      body: JSON.stringify(payload),
      headers: {
        'Content-Type': 'application/json;charset=UTF-8'
      },
    })
      .then(handleErrors)
      .then(response => response.json())
      .then(data => {
        dispatch({ type: RECEIVE_LOGIN_TOKEN, payload: data })
        saveJwt(data)

        //selectData
        dispatch({ type: REQUEST_SELECT_DATA })

        const token = getJwt()
        const headers = new Headers({
          'Authorization': `Bearer ${token}`
        })
        const retrieveSelectData = fetch('/api/SelectData/SelectData', {
          method: 'GET',
          headers: {
            'Content-Type': 'application/json;charset=UTF-8'
          },
        })
          .then(handleErrors)
          .then(response => response.json())
          .then(selectData => {
            dispatch({ type: RECEIVE_SELECT_DATA, payload: selectData })
          })

      })
      .catch(error => {
        clearJwt()
        dispatch({ type: ERROR_LOGIN_TOKEN, payload: error.message })
      })
    addTask(task)
    return task
  }

Here is the code for the reducer:

// ******************* reducer
const initialState = {
  isLoading: false,
  isAuthorised: false,
  username: null,
  jwt: null,
  SuburbPostcodeDropDownList: null,
  StateDropDownList: null,
  CompanyStateShortName: null,
  error: null,
}

export default (state = initialState, action) => {
  switch (action.type) {
    case REQUEST_LOGIN_TOKEN:
      return {
        ...state,
        isLoading: true,
        isAuthorised: false,
        username: action.payload,
        jwt: null,
        error: null,
      }
    case RECEIVE_LOGIN_TOKEN:
      return {
        ...state,
        isLoading: false,
        isAuthorised: true,
        jwt: action.payload,
        error: null,
      }
    case ERROR_LOGIN_TOKEN:
      return {
        ...state,
        isLoading: false,
        isAuthorised: false,
        username: null,
        jwt: null,
        error: action.payload,
      }

    case REQUEST_SELECT_DATA:
      return {
        ...state,
        isLoading: true,
        isAuthorised: false,
        SuburbPostcodeDropDownList: null,
        StateDropDownList: null,
        CompanyStateShortName: null,
        error: null,
      }

    case RECEIVE_SELECT_DATA:
      return {
        ...state,
        isLoading: false,
        isAuthorised: true,
        SuburbPostcodeDropDownList: action.payload.SuburbPostcodeDropDownList,
        StateDropDownList: action.payload.StateDropDownList,
        CompanyStateShortName: action.payload.CompanyStateShortName,
        error: null,
      }

Is this because the state requires more setup if there are list arrays etc.

If so how would you structure the reducer to cope with array objects?

Upvotes: 1

Views: 2441

Answers (1)

davnicwil
davnicwil

Reputation: 30967

Your problem is simple - the fields on action.payload aren't properly cased in your reducer, under the RECEIVE_SELECT_DATA case. They start with an uppercase letter, when they should start with a lowercase letter.

This means they are read as undefined, which means when you use the object spread syntax to build the new state object, they aren't added to the new object at all, and that's why they disappear from the state.

Lowercase the first letter of all those field names, and it should work.

Upvotes: 3

Related Questions