Luiz Almeida
Luiz Almeida

Reputation: 81

How to add to a state array in react-redux

kind of stuck on this little tidbit. I'm pretty new to redux so I'm just trying to figure it out. I'm trying to seperate my players array which come in on the response based on the players position. It all works except that the state is just constantly changing to the most recent player in that position instead of adding to the array of players in that position. Here are my actions and reducer:

//action.js    
export const FETCH_PLAYERS_SUCCESS = 'FETCH_PLAYERS_SUCCESS';
    export const fetchPlayersSuccess = players => ({
        type: FETCH_PLAYERS_SUCCESS,
        players
    });

export const SET_WR = 'SET_WR';
export const setWR = wr => ({
    type: SET_WR,
    wr
});

export const SET_QB = 'SET_QB';
export const setQB = qb => ({
    type: SET_QB,
    qb
});

export const SET_RB = 'SET_RB';
export const setRB = rb => ({
    type: SET_RB,
    rb
});

export const SET_TE = 'SET_TE';
export const setTE = te => ({
    type: SET_TE,
    te
});

export const fetchPlayers = () => {
  return dispatch => {
    const proxyurl = "https://cors-anywhere.herokuapp.com/";
    const url = "http://api.fantasy.nfl.com/v1/players/stats?statType=seasonStats&season=2017&week=1&format=json"; // site that doesn’t send Access-Control-*
    fetch(proxyurl + url)
    .then(res => res.json())
    .catch(error => {
        console.error('Error:', error)
        dispatch(fetchPlayersError(error))
    })
    .then(response => {
        let thisPlayer = response.players
        for(let i=0; i<thisPlayer.length; i++){
            if(thisPlayer[i].position == 'WR'){
                dispatch(setWR(thisPlayer[i]))
            }
            if(thisPlayer[i].position == 'QB'){
                dispatch(setQB(thisPlayer[i]))
            }
            if(thisPlayer[i].position == 'RB'){
                dispatch(setRB(thisPlayer[i]))
            }
            if(thisPlayer[i].position == 'TE'){
                dispatch(setTE(thisPlayer[i]))
            }
        }
        dispatch(fetchPlayersSuccess(response))
    });
}}

my reducer:

//reducer.js

const initialState = {
    players: [],
    loading: false,
    error: null,
    wr: [],
    qb: [],
    rb: [],
    te: []
};

export default (state = initialState, action) => {
    if (action.type === FETCH_PLAYERS_REQUEST) {
        return Object.assign({}, state, {
            loading: true,
            error: null
        });
    }
if (action.type === FETCH_PLAYERS_SUCCESS) {
    //console.log(state, action);
    return Object.assign({}, state, {
        players: action.players,
        loading: false
    });
}

if (action.type === SET_QB) {
    //console.log(state, action);
    return Object.assign({}, state, {
        qb: action.qb,
        loading: false
    });
}

if (action.type === SET_RB) {
    //console.log(state, action);
    return Object.assign({}, state, {
        rb: action.rb,
        loading: false
    });
}

if (action.type === SET_WR) {
    //console.log(state, action);
    return Object.assign({}, state, {
        wr: action.wr,
        loading: false
    });
}

if (action.type === SET_TE) {
    //console.log(state, action);
    return Object.assign({}, state, {
        te: action.te,
        loading: false
    });
}
if (action.type === FETCH_PLAYERS_ERROR) {
    return Object.assign({}, state, {
        loading: false,
        error: action.error
    });
}
return state;
};

thanks for any help in advance.

Upvotes: 2

Views: 1820

Answers (1)

thesb
thesb

Reputation: 219

I think you are overwriting the state object. I don't think your code is adding to an array, just overwriting it.

Also, I would pass the array from the response to one dispatch function, instead of looping and calling serval dispatch functions or format the object before you call dispatch. I think that would be easier to debug and maintain. You only need to call dispatch once, unless you have a compelling reason to call it several times.

Use a switch statement for your reducer and update each array only if needed, otherwise just keep the array from the current state. I see that you are using Object.assign. Instead, try just updating the arrays individually as needed and return a new object for each action.

I don’t know all of your requirements, but this may help:

export const loadPlayers = formattedRespObj => ({
    type: 'FETCH_PLAYERS_SUCCESS',
    players: formattedRespObj.players,
    wr: formattedRespObj.wr,
    qb: formattedRespObj.qb,
    rb: formattedRespObj.rb,
    te: formattedRespObj.te
});

function formatRespObj(playersResp) {
    let formattedRespObj = {players: [], wr: [], qb: [], rb: [], te: []};

    // Note, this can probably be prettier
    for (let i = 0; i < playersResp.length; i++) {
        switch (playersResp[i].position) {
            case 'WR':
                formattedRespObj.wr.push(playersResp[i]);
                break;
            case 'QB':
                formattedRespObj.qb.push(playersResp[i]);
                break;
            case 'RB':
                formattedRespObj.rb.push(playersResp[i]);
                break;
            case 'TE':
                formattedRespObj.te.push(playersResp[i]);
                break;
            default:
                console.error("Unknown player position");
                break;
        }
    }

    formattedRespObj.players = [...formattedRespObj.wr, ...formattedRespObj.qb, ...formattedRespObj.rb, ...formattedRespObj.te];

    return formattedRespObj;
}

const initialState = {
    players: [],
    loading: false,
    error: null,
    wr: [],
    qb: [],
    rb: [],
    te: []
};

export default function reducer(playersState = initialState, action) {
    switch (action.type) {
        case 'LOAD_PLAYERS':
            return {
                players: [...playersState.wr, playersState.wr],
                loading: true,
                error: null,
                wr: [...playersState.wr, action.wr],
                qb: [...playersState.qb, action.qb],
                rb: [...playersState.rb, action.rb],
                te: [...playersState.te, action.te],
            };
        case 'FETCH_PLAYERS_ERROR':
            return {
                loading: false,
                error: action.error,
                wr: playersState.wr,
                qb: playersState.qb,
                rb: playersState.rb,
                te: playersState.te
            };
        default:
            return {
                loading: false,
                error: null,
                wr: playersState.wr,
                qb: playersState.qb,
                rb: playersState.rb,
                te: playersState.te
            }
    }
}

export const fetchPlayers = () => {
    return dispatch => {
        const proxyurl = "https://cors-anywhere.herokuapp.com/";
        const url = "http://api.fantasy.nfl.com/v1/players/stats?statType=seasonStats&season=2017&week=1&format=json"; // site that doesn’t send Access-Control-*
        fetch(proxyurl + url)
            .then(res => res.json())
            .catch(error => {
                console.error('Error:', error);
                dispatch(fetchPlayersError(error));
            })
            .then(response => {
                let formattedRespObj = formatRespObj(response);
                dispatch(loadPlayers(formattedRespObj));

                dispatch(fetchPlayersSuccess(response))
            });
    }
};

Upvotes: 2

Related Questions