0
votes

My react redux setup was working well until I needed to trigger a component update based on an update to a redux store variable. From research I feel that my issue is that I am not returning from my reducer in an immutable fashion such that an update is not triggered in the connected component after I dispatch an update to the redux store.

Action

import {GAMESETUP_IN, GAMESETUP_OUT} from "../api/strings";

export const gameSetupIn = ({gameType, gameRound, gameStocks, gameHistory} = {}) => ({
    type: GAMESETUP_IN,
    gameSetup: {
      gameType,
      gameRound,
      gameStocks,
      gameHistory
    }
});

export const gameSetupOut = () => ({
    type: GAMESETUP_OUT
});

Reducer

// default state
import {GAMESETUP_IN, GAMESETUP_OUT} from "../api/strings";

const gameSetupReducerDefaultState = {
    gameType: "",
    gameRound: "",
    gameStocks: [],
    gameHistory: []
};

// reducer which is a pure function
export default(state = gameSetupReducerDefaultState, action) => {
    switch (action.type) {
        case GAMESETUP_IN:
            // Return a new array
            return {
                ...state,
                gameType: action.gameSetup.gameType.toString(),
                gameRound: action.gameSetup.gameRound.toString(),
                gameStocks: action.gameSetup.gameStocks,
                gameHistory: action.gameSetup.gameHistory
            };
        case GAMESETUP_OUT:
            return {
                ...state,
                gameType: "",
                gameRound: "",
                gameStocks: [],
                gameHistory: []
            };
        default:
            return state;
    }
};

I feel like there are two very closely related questions. 1) How can I return immutable data from redux reducer? 2) Updating Redux state does not trigger componentWillReceiveProps

and also the base redux documentation 3) https://redux.js.org/basics/reducers/

I feel like the answer is right in front of me that I need to somehow use return Object.assign({}, state, { key: newValue }); during the return from redux. I am just looking for some help in modifying my reducer to ensure that it is immutable and thus will trigger a component update after a dispatch. Thank you.

1

1 Answers

1
votes

This all looks non-mutating to me. Are you mutating any of the variables, e.g. gameHistory elsewhere? Your reducer should be the only function that does that.

You are giving the redux state a reference to the history, so if you append anything to that object elsewhere in code it could cause issues.

One solution, as you say, is to use gameHistory: Object.assign({}, action.gameSetup.gameHistory) to make a copy, but this will just be a "shallow" copy (if your object contains other objects, they will be copied by reference). The (disgusting hack, but as far as I know only way for general objects) of making a deep copy is to use deep_copy_obj = JSON.parse(JSON.stringify(my_obj)).

The immutable way of doing things is to have your reducer managing things like appending to history, and if you want to edit the history when a button is clicked, make the button dispatch an action.