Kelb56
Kelb56

Reputation: 657

Storing and retrieving state from store

I am trying to save a userToken inside a Redux store and retrieve it. In my index.js I wrap my App with Provider, which takes store as prop:

import { createStore } from "redux";
import { Provider } from "react-redux";
import rootReducer from "./reducers/rootReducer";

const store = createStore(rootReducer);

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById("root")
);

My rootReducer looks like this:

//Helper functions
import { validateLoginAttempt } from "../helpers/validateLoginAttempt";

const rootReducer = (state, action) => {
  switch (action.type) {
    case "login":
      const isLoggedIn = validateLoginAttempt(action.payload);
    default:
      console.log("default");
      break;
  }
};

export default rootReducer;

I have defined a helper function validateLoginAttempt:

export const validateLoginAttempt = payload => {
  if (typeof payload.data.token !== "undefined") {
    //Saves in localstorage correctly.
    localStorage.setItem("userToken", payload.data.token);

    return true;
  }

  return false;
};

In one of my functional components, I have a fetch() procedure, which by the end of request to an API, dispatch()'es action I defined in my rootReducer:

const dispatch = useDispatch();
<...>
.then(data => {
  dispatch({ type: "login", payload: { data } });
  history.push("/");
})

Flow of this useCase works as intended, at least from what I understand, the value gets stored in localStorage (which I assume is not a Redux store?). In another of my components I am trying to retrieve userToken like this:

const userToken = useSelector(state => state.userToken);

This gives me an error:

Error: An error occured while selecting the store state: Cannot read property 'userToken' of undefined.

If I try to getStore as follows in my App component, I get store undefined:

const store = useStore();
console.log("store", store.getState());

Could someone put me on a right track, cannot figure this out.

Upvotes: 1

Views: 928

Answers (1)

Aprillion
Aprillion

Reputation: 22304

There are multiple problems, but the biggest one is related to the basics of reducers:

The reducer is a pure function that takes the previous state and an action, and returns the next state.

You don't return anything from the reducer (implicitly return undefined), thus causing the TypeError Cannot read property 'userToken' of undefined.:

const initialState = {};
const rootReducer = (state = initialState, action) => {
  switch (action.type) {
    case "login": {
      return {...state, userToken: action.payload.data.token};
    }
    default:
      return state;
  }
};

And "a pure function" means no side effects, so the localStorage.setItem inside validateLoginAttempt has no place in a reducer and should be placed inside the action creator:

const dispatch = useDispatch();
...
.then(data => {
  const isLoggedIn = validateLoginAttempt(data);
  if (isLoggedIn) {
    dispatch({ type: "login", payload: { data } });
    history.push("/");
  } else {
    console.error("not logged in")
  }
})

Upvotes: 1

Related Questions