Uzzar
Uzzar

Reputation: 703

Application state doesn't get updated after api call

I am missing a key step/concept in how asyn calls work in react-redux.

Currently, I am able to make api calls (can also see the data being returned via chrome-dev-tools) BUT the response data isn't reflected in the application state; meaning the state of the quiz object, which by default is an empty object, doesn't get updated.

My expectation is that when the asyn call resolves, I parse through the response in the quizReducer, and return a new state (not a mutated state) that reflects the response data.

Yet, each time the call is made, the updated state returns an empty quiz object (which is the initial state).

I know I am missing something but I can't figure out what; would really appreciate some pointers/explanation. Thank you

The app had an initialState/Preloaded state that looks like this:

  export default {
   quizzes: [
     {id: 0, name: "quiz_name2", completed: false, selected: false}, 
     {id: 1, name: "quiz_name2", completed: false, selected: false}
   ],
   quiz: { questions: {} }
 }; 

Setup for the reducer in question:

    import initialState from './initialState';
    import quizConstants from '../constants/quizConstants';
    const actionTypes = quizConstants.actions

    // when app loads, user has not selected any quiz therefore 
    // initialState is an empty object 
    // here action is the payload we get when a quiz is selected (see QUIZ_SELETED action creator)


    export default function quiz(state=initialState.quiz, action) {
      switch(action.type){
        // when a quiz is selected, return new state
        case actionTypes.SELECT_QUIZ:
          return Object.assign(
            {}, 
            state, 
            {
              id: action.quiz.id,
              name: action.quiz.name,
              completed: action.quiz.completed,
              selected: !action.quiz.selected,
              fetching: action.quiz.fetching,
              fetched: action.quiz.fetched,
              questions: action.quiz.questions
            }
          )
        case actionTypes.REQUEST_QUIZ:
          return Object.assign(
            {},
            state, 
            {
              id: action.quiz.id,
              name: action.quiz.name,
              completed: action.quiz.completed,
              selected: !action.quiz.selected,
              fetching: !action.quiz.fetching,
              fetched: action.quiz.fetched,
              questions: action.quiz.questions 
            }
          )
        case actionTypes.RECEIVE_QUIZ:
          return Object.assign(
            {},
            state,
            {
              id: action.quiz.id,
              name: action.quiz.name,
              completed: action.quiz.completed,
              selected: !action.quiz.selected,
              fetching: action.quiz.fetching,
              fetched: !action.quiz.fetched,
              quiz: action.quiz.questions 
            }
          )
        default:
          return state 
      }
    };

index.js (rootreducer):

    import { combineReducers } from 'redux';
    import { routerReducer } from 'react-router-redux';
    import quizzes from './quizzesReducer'
    import quiz  from './quizReducer';

    export default combineReducers({
      quizzes,
      quiz,
      routing: routerReducer
    }); 

QuizActionCreators

    import quizConstants from '../constants/quizConstants';
    import { quizzesEndPoint } from '../constants/appConstants';
    import axios from 'axios';

    const actionTypes = quizConstants.actions

    // select a quiz 
    export const selectQuiz = (quiz) => {
      return {
        type: actionTypes.SELECT_QUIZ,
        quiz
      }
    }; 

    const receiveQuiz = (quiz, data) => {
      return {
        type: actionTypes.RECEIVE_QUIZ,
        quiz,
        data
      }
    };

    // call when componentWillMount
    export const fetchQuiz = (quiz) => {
      console.log("Make an api request here")
      const url = quizzesEndPoint.concat(quiz.name)
      axios.get(url)
        .then(response => response.data)
        .then(data => receiveQuiz(quiz, data))
    }
    export default { selectQuiz, fetchQuiz};

Upvotes: 0

Views: 96

Answers (1)

jpdelatorre
jpdelatorre

Reputation: 3593

In your QuizActionCreator, your fetchQuiz is calling receiveQuiz and passing quiz and data as your parameter which the latter has the data from the server. I don't see any part in your reducers where you are setting the action.data to the state.

Try adding handler for RECEIVE_QUIZ inside your quizzesReducer and return the action.data to the state.

//quizzesReducer.js
export default function (state = initialState.quizzes, action){
   ...
   if (action.type === actionTypes.RECEIVE_QUIZ) {
      return action.data
   }
   ...
};

Upvotes: 1

Related Questions