skip to Main Content

I am trying to use a Redux store to get account information from a server, but the returned object is empty. The code is supposed to get a JWT token from a store, and then the token is supposed to be used to get account into from a server and store it as the global state in the store.

I logged the object using the console, but the "accountInfo" object which is supposed to have all of the information about an account is empty.

My code:

if (localStorage.jwtToken) {
  const token = localStorage.jwtToken;
  setAuthToken(token);
  const decoded = jwt_decode(token);
  store.dispatch(setCurrentUser(decoded));
  const currentTime = Date.now() / 1000
  if (decoded.exp < currentTime) {
    store.dispatch(logoutUser());
  } else {
    store.dispatch(getAccountInfo());
    console.log(store.getState());
    loggedIn = true;
  }
}

export const getAccountInfo = () => {
    var accountInfo = {};

    const token = localStorage.jwtToken;
    setAuthToken(token);

    const decoded = jwt_decode(token);
    const currentUsername = decoded.name;
    fetch(${Globals.API_URL}/account/info/?username=${currentUsername}, { headers: { "x-access-token": token }})
      .then((res) => res.json())
      .then((data) => 
      {
        console.log(data);
        if(data.message != null)
        {
          accountInfo = {message: data.message};
        } else {
          accountInfo = data;
        }
    })
    .catch(error => {
      accountInfo = {error: error};
    })

    return {
      type: "GET_ACCOUNT_INFO",
      payload: accountInfo
    }
}

const initialState = {
  accountInfo: {}
};

export const accountReducer = (state = initialState, action) => {
  switch (action.type) {
    case "GET_ACCOUNT_INFO":
        return {
            ...state,
            accountInfo: action.payload
        };
    default:
          return state;
      }
    }

The object as shown in the console:

Object
    account: 
        accountInfo: {}
    [[Prototype]]: 

The backend part works fine. How do I make the accountInfo object not return empty?

2

Answers


  1. You’re trying to build async logic into an action creator without using the necessary middleware. See Redux Middleware and Side Effects:

    By itself, a Redux store doesn’t know anything about async logic. It
    only knows how to synchronously dispatch actions, update the state by
    calling the root reducer function, and notify the UI that something
    has changed. Any asynchronicity has to happen outside the store.

    If you want to update your store in response to your request, you need to dispatch after it has settled. That means your getAccountInfo will need to dispatch an action, instead of returning an object.

    The offical Redux middleware for async functions is Redux Thunk Middleware. Once you have that configured, you can accomplish what you’re looking for with that:

    const setActionInfo = (actionInfo) => ({
      type: "GET_ACCOUNT_INFO",
      payload: actionInfo,
    });
    
    const getAccountInfo = (dispatch) => {
        var accountInfo = {};
    
        const token = localStorage.jwtToken;
        setAuthToken(token);
    
        const decoded = jwt_decode(token);
        const currentUsername = decoded.name;
        fetch(${Globals.API_URL}/account/info/?username=${currentUsername}, { headers: { "x-access-token": token }})
          .then((res) => res.json())
          .then((data) => 
          {
            console.log(data);
            if(data.message != null)
            {
              accountInfo = {message: data.message};
            } else {
              accountInfo = data;
            }
        })
        .catch(error => {
          accountInfo = {error: error};
        })
    
        dispatch(setActionInfo(actionInfo));
    }
    
    Login or Signup to reply.
  2. You may be dispatching this getAccountInfo action to the store, but it doesn’t correctly wait for the fetch logic to complete before trying to use the accountInfo object, and it doesn’t again dispatch an action to pass the accountInfo value to the store to be handled.

    I’ll assume you have already setup and configured the Redux store to handle asynchronous actions, e.g. Thunk middleware.

    1. getAccountInfo should consume a dispatch function that the Thunk middleware will pass it. This allows you to dispatch an action with the populated accountInfo value.
    2. The action should either move the final dispatch of the accountInfo payload to the end of the Promise chain, or convert the entire function to async/await/try/catch, the latter of which is more common.
    const getAccountInfo = accountInfo => ({
      type: "GET_ACCOUNT_INFO",
      payload: accountInfo,
    });
    
    const getAccountInfoError = error => ({
      type: "GET_ACCOUNT_INFO_ERROR",
      payload: error,
    });
    
    export const getAccountInfo = async (dispatch) => {
      const token = localStorage.jwtToken;
      setAuthToken(token);
    
      const decoded = jwt_decode(token);
      const currentUsername = decoded.name;
    
      try {
        const res = await fetch(
          ${Globals.API_URL}/account/info/?username=${currentUsername},
          {
            headers: {
              "x-access-token": token
            }
          }
        )
        const data = await res.json();
    
        dispatch(getAccountInfo(data));
      } catch(error) {
        dispatch(getAccountInfoError(error));
      }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search