0

I'm using React and Redux and storing data in a loggedUser variable upon user login.

my login reducer looks like this:

const loginReducer = (state = null, action) => {
  switch (action.type) {
    case "SET_USER":
      if (action.data) userService.setToken(action.data.token);
      return action.data;
    default:
      return state;
  }
};

export const fetchUser = () => {
  return dispatch => {
    const userStr = window.localStorage.getItem("loggedVintageUser");
    const user = JSON.parse(userStr);
    if (user) {
      dispatch({ type: "SET_USER", data: user });
    }
  };
};

export const setUser = data => {
  return dispatch => {
    dispatch({ type: "SET_USER", data });
  };
};

export const login = data => {
  return async dispatch => {
    const user = await loginService.login({
      username: data.username,
      password: data.password
    });
    window.localStorage.setItem("loggedVintageUser", JSON.stringify(user));
    dispatch({ type: "SET_USER", data: user });
  };
};

In my core App component i'm dispatching the fetchUser and setUser creators

  useEffect(() => {
    fetchUser();
  }, [props.fetchUser]);

  useEffect(() => {
    const loggedUserJSON = window.localStorage.getItem("loggedVintageUser");
    if (loggedUserJSON) {
      const user = JSON.parse(loggedUserJSON);
      props.setUser(user);
      userService.setToken(user.token);
    }
  }, []);

I'm displaying a list of favorite items for a user and when i go to refresh the page, i'm getting the following error:

TypeError: Cannot read property 'favorites' of null

Here is relevant code for my Favorites component. The error is triggered on the loggedUser.favorites data. I can see when visiting the favorites page, the loggedUser field is there and data displays fine but on refresh the loggedUser variable turns to null.

const searchCards = ({ loggedUser, search }) => {
  const favorites = loggedUser.favorites;
  console.log("FAVORITES", favorites);
  return search
    ? favorites.filter(a =>
        a.title
          .toString()
          .toLowerCase()
          .includes(search.toLowerCase())
      )
    : favorites;
};

const Cards = props => {
  useEffect(() => {
    setData(props.cardsToShow);
  }, [props]);

const [filteredData, setData] = useState(props.cardsToShow);

const mapStateToProps = state => {
  return {
    baseball: state.baseball,
    loggedUser: state.loggedUser,
    page: state.page,
    entries: state.entries,
    query: state.query,
    pageOutput: state.pageOutput,
    search: state.search,
    cardsToShow: searchCards(state)
  };
};

const mapDispatchToProps = {
  searchChange,
  fetchData,
  updateUser
};

I tried to add this before i render the data, but it's not working

if (!props.loggedUser) return null;

How can i retain that state if a user is refreshing the page. The odd part is that on my home page where i have a similar sort of display a refresh isn't causing the same problems.

John Rogerson
  • 1,153
  • 2
  • 19
  • 51
  • parse your data when you get from localStorage outside of your if condition in useEffect – akhtarvahid Dec 11 '19 at 03:27
  • like this? `useEffect(() => { const loggedUserJSON = window.localStorage.getItem("loggedVintageUser"); const user = JSON.parse(loggedUserJSON); if (user) { props.setUser(user); userService.setToken(user.token); } }, []);` not working still – John Rogerson Dec 11 '19 at 03:45
  • so, i think i can see why i am losing state for my loggedUser. when page is refreshed, the @@INIT dispatch is called and my loggedUser is set back to the initial state which i set in my reducer of []. Thus, i guess i basically need to tell redux not to change my loggedUser state on refresh---is this possible? – John Rogerson Dec 11 '19 at 04:35
  • can you share your code in sandbox to check and debug? – akhtarvahid Dec 11 '19 at 04:45
  • so, i posted the relevant code pages, there's a lot of code, so hopefully this helps..not exactly a working example, but maybe you can see something that is off https://codesandbox.io/s/priceless-lamarr-17n0b – John Rogerson Dec 11 '19 at 16:15

2 Answers2

0

check once loggedUser is exist in state or not. Print state using console.log(state). you may also open inspect tool and go to application tab and click on local storage, you will get localStorage data.

Amit Sinha
  • 88
  • 8
  • hi Amit, if i go to application tab i do see the local storage info when i login, and when i click to favorites it remains there. Also, if i refresh the page it still remains – John Rogerson Dec 11 '19 at 03:20
  • I think it is an issue with the reducer you have to call the reducer at the current page too. Hope this will work. – Jibin Francis Dec 11 '19 at 03:28
  • your doubt was How can i retain that state if a user is refreshing the page.So now you are getting state is still remains after page refresh.put console.log(loggedUser) before const favorites = loggedUser.favorites; line and make sure loggedUser is object and it has favorites. – Amit Sinha Dec 11 '19 at 03:31
  • data is there on initial load of the favorites page but goes to null after refresh – John Rogerson Dec 11 '19 at 03:36
-1

Well, i figured this out and got some help from this post here. Redux store changes when reload page

My loggedUser state was disappearing after reload, so i just loaded the inital state for loggedUser pulling the data from the local storage:

function initState() {
  return {
    token: localStorage.token,
    firstName: localStorage.firstName,
    id: localStorage.id,
    favorites: localStorage.favorites,
    username: localStorage.username
  };
}

const loginReducer = (state = initState(), action) => {
  switch (action.type) {
    case "SET_USER":
      if (action.data) userService.setToken(action.data.token);
      return action.data;
    default:
      return state;
  }
};
John Rogerson
  • 1,153
  • 2
  • 19
  • 51