Search code examples
javascriptreactjsreduxcodesandbox

React Action Requests and Redux Structure


I have successfully created an action doing a call request to the following endpoint

https://api-football-v1.p.rapidapi.com/v2/statistics/{league_id}/{team_id}

API Documentation is here

I have created a little demo in codesandbox where you can see i can display the matchs wins, draws and loses correctly in my component Stats.js for the Sao Paulo Team ( it is an example )

Here all the steps i have done, i show you only the relevant code to achieve it

In my reducers i have created the following cases

  RECEIVE_TEAMS_STATS_WIN_HOME,
  RECEIVE_TEAMS_STATS_WIN_AWAY,
  RECEIVE_TEAMS_STATS_DRAW_HOME,
  RECEIVE_TEAMS_STATS_DRAW_AWAY,
  RECEIVE_TEAMS_STATS_LOSE_HOME,
  RECEIVE_TEAMS_STATS_LOSE_AWAY

In my initial state i have

  teamsStatsWinHome: [],
  teamsStatsWinAway: [],
  teamsStatsDrawHome: [],
  teamsStatsDrawAway: [],
  teamsStatsLoseHome: [],
  teamsStatsLoseAway: [],

These are my cases

 case RECEIVE_TEAMS_STATS_WIN_HOME:
      return {
        ...state,
        teamsStatsWinHome: action.json,
        isTeamsStatsLoading: false
      };
    case RECEIVE_TEAMS_STATS_WIN_AWAY:
      return {
        ...state,
        teamsStatsWinAway: action.json,
        isTeamsStatsLoading: false
      };
    case RECEIVE_TEAMS_STATS_DRAW_HOME:
      return {
        ...state,
        teamsStatsDrawHome: action.json,
        isTeamsStatsLoading: false
      };
    case RECEIVE_TEAMS_STATS_DRAW_AWAY:
      return {
        ...state,
        teamsStatsDrawAway: action.json,
        isTeamsStatsLoading: false
      };
    case RECEIVE_TEAMS_STATS_LOSE_HOME:
      return {
        ...state,
        teamsStatsLoseHome: action.json,
        isTeamsStatsLoading: false
      };
    case RECEIVE_TEAMS_STATS_LOSE_AWAY:
      return {
        ...state,
        teamsStatsLoseAway: action.json,
        isTeamsStatsLoading: false
      };

And here my action with the call request to the API endpoint

export function getTeamsStats(league, team) {
  return function(dispatch) {
    return axios
      .get(
        `https://www.api-football.com/demo/api/v2/statistics/${league}/${team}`
      )
      .then(res => {
        let homewins = res.data.api.statistics.matchs.wins.home;
        dispatch(receivedTeamsStatWinHome(homewins));
        let awaywins = res.data.api.statistics.matchs.wins.away;
        dispatch(receivedTeamsStatWinAway(awaywins));
        let drawhome = res.data.api.statistics.matchs.draws.home;
        dispatch(receivedTeamsStatDrawHome(drawhome));
        let drawaway = res.data.api.statistics.matchs.draws.away;
        dispatch(receivedTeamsStatDrawAway(drawaway));
        let losehome = res.data.api.statistics.matchs.loses.home;
        dispatch(receivedTeamsStatLoseHome(losehome));
        let loseaway = res.data.api.statistics.matchs.loses.away;
        dispatch(receivedTeamsStatLoseAway(loseaway));
      })
      .catch(e => {
        console.log(e);
      });
  };

The funcion getTeamsStats is then put in the fetchLeaguesList to get the Sao Paulo result as example

This is the relevant code in my component Stats.js

let Stats = ({
  teamsStatsWinHome,
  teamsStatsWinAway,
  teamsStatsDrawHome,
  teamsStatsDrawAway,
  teamsStatsLoseHome,
  teamsStatsLoseAway,
  loading
}) => {
  let stats = "";

  if (
    teamsStatsWinHome &&
    teamsStatsWinAway &&
    teamsStatsDrawHome &&
    teamsStatsDrawAway &&
    teamsStatsLoseHome &&
    teamsStatsLoseAway
  ) {
    stats = (
      <div className="col-sm-6">
        <div className="card detail-card border-0 rounded-0 bg-transparent">
          <div className="card-body text-decoration-none text-secondary">
            {JSON.stringify(teamsStatsWinHome)}
            {JSON.stringify(teamsStatsWinAway)}
            {JSON.stringify(teamsStatsDrawHome)}
            {JSON.stringify(teamsStatsDrawAway)}
            {JSON.stringify(teamsStatsLoseHome)}
            {JSON.stringify(teamsStatsLoseAway)}
          </div>
        </div>
      </div>
    );
  }

It works as expected, as you can see in the codesandbox demo but i do not know if i am doing in the right way with Redux states, call action and Component.

My question is , is it right? Can i make it better? If yes, how should i refactor?

Any refactor and code changes in the codesandbox demo is good to accept the answer


Solution

  • Dispatch a single action to update the store for result instead of dispatching multiple actions per field in the result.

    src/actions/index.js

    
    export const RECEIVE_TEAMS_STATS = "RECEIVE_TEAMS_STATS";
    
    
    export const receivedTeamsStat = json => ({
      type: RECEIVE_TEAMS_STATS,
      json: json
    });
    
    export function getTeamsStats(league, team) {
      return function(dispatch) {
        return axios
          .get(
            `https://www.api-football.com/demo/api/v2/statistics/${league}/${team}`
          )
          .then(res => {
            const { 
              wins: { home: teamsStatsWinHome, away: teamsStatsWinAway }, 
              draws: { home: teamsStatsDrawHome, away: teamsStatsDrawAway }, 
              loses: { home: teamsStatsLoseHome, away: teamsStatsLoseAway }
            } = res.data.api.statistics.matchs;
            const teamStats = {
              teamsStatsWinHome,
              teamsStatsWinAway,
              teamsStatsDrawHome,
              teamsStatsDrawAway,
              teamsStatsLoseHome,
              teamsStatsLoseAway
             }
            dispatch(receivedTeamsStat(teamStats));
          })
          .catch(e => {
            console.log(e);
          });
      };
    

    All 6 actions (RECEIVE_TEAMS_STATS_WIN_HOME, RECEIVE_TEAMS_STATS_WIN_AWAY, RECEIVE_TEAMS_STATS_DRAW_HOME, RECEIVE_TEAMS_STATS_DRAW_AWAY, RECEIVE_TEAMS_STATS_LOSE_HOME, RECEIVE_TEAMS_STATS_LOSE_AWAY) can be rolled into a RECEIVE_TEAMS_STATS action and handled as follows:

    src/reducers/index.js

    import {
      //..
      RECEIVE_TEAMS_STATS
    } from "../actions";
    
    
    const reducer = (state = initialState, action) => {
      switch (action.type) {
        //...
        case RECEIVE_TEAMS_STATS:
          return {
            ...state,
            ...action.json,
            isTeamsStatsLoading: false
          };
        //...
    }
    

    The benefit of dispatching a single update to the store is that Stats component renders once as opposed to 6 times when results return from the API.