0

So, I'm having an issue with redux not keeping state of a 'token' value. Upon vising the app you are directed to a login page. Submitting your login details returns an auth token, which assigns the value of the returned token value to the variable token, adds token to props, and then redirects you to the main part of the app '/'.

If I immediately return to the login page '/login' the token disappears from props, causing a user to have to re-login again.

What is the issue here?

app.js

render(
  <ApolloProvider store={store} client={client}>
    { /* Tell the Router to use our enhanced history */ }
    <Router history={history}>
      <Route path="/" component={App}>
        <IndexRoute component={PhotoGrid} />
        <Route path="/view/:postId" component={Single}></Route>
        <Route path="/login" component={LoginUser}></Route>
      </Route>
    </Router>
  </ApolloProvider>,
  document.getElementById('root')
);

App.js

function mapStateToProps(state) {
   return {
    token: state.token[0]
  };
}

Root reducer (index.js)

import { combineReducers } from 'redux';
import client from '../apolloClient';
import { routerReducer } from 'react-router-redux'; // we need this for react-router
import tokenDetails from './tokenDetails';
const rootReducer = combineReducers({
  token: tokenDetails,
  routing: routerReducer,
  apollo: client.reducer(),
});

export default rootReducer;

tokenDetails.js

var tokenDetails = function(state, action) {

  if (state === undefined) {
    state = [];
  }

  switch (action.type) {
    case 'Graphcool_Token':
      const newState = [action.payload];
      return newState;
    default:
      return state;
  }
}

export default tokenDetails;

actionCreator,js

export function authToken(token) {
  return (dispatch) => {
    dispatch({
      type: 'Graphcool_Token',
      payload: token
    });
  } 
}

LoginUser.js

  signinUser: function(emailID, passwordID) {

    const email = emailID;
    const password = passwordID;

    this.props.client.mutate({
      mutation: signinUser_Mutation,
      variables: {
        email,
        password,
      },
      options: {
        cachePolicy: 'offline-critical', 
        fetchPolicy: 'cache-first',
      },
    })
    .then(this.updateStateLoginDetails)
    .catch(this.handleSubmitError);
  },

  updateStateLoginDetails: function({data}) {
    this.props.authToken(data.signinUser.token);
    this.context.router.push('/');
  },

  handleSubmitError: function(err) {
    console.error(err.message);
  },

  handleSubmit: function(e) {
    e.preventDefault();
    this.signinUser(this.refs.email.value, this.refs.password.value);
    this.refs.loginForm.reset();
    this.refs.email.focus();
  },
  render: function() {
  }

store.js

const middlewares = [thunk, client.middleware()];

const enhancers = compose(
    applyMiddleware(...middlewares),

    (typeof window.__REDUX_DEVTOOLS_EXTENSION__ !== 'undefined' || process.env.NODE_ENV !== 'production') ? window.__REDUX_DEVTOOLS_EXTENSION__() : (f) => f,
    autoRehydrate(),
);

const store = createStore(
  rootReducer,
  {}, // initial state
  enhancers
);

// begin periodically persisting the store
persistStore(store, {storage: localForage});

export const history = syncHistoryWithStore(
  browserHistory, 
  store
);

if(module.hot) {
  module.hot.accept('./reducers/', () => {
    const nextRootReducer = require('./reducers/index').default;
    store.replaceReducer(nextRootReducer);
  });
}

export default store;
TheoG
  • 1,498
  • 4
  • 30
  • 54
  • it looks a bit buggy. `token: state.token[0]` assumes there is one element always. The initial state is an empty array. – vijayst May 31 '17 at 10:48
  • @vijayst So how do I best handle the assignment, and injecting into props, of a token value that can only be ascertained after having logged in? – TheoG May 31 '17 at 11:01
  • I think it works, will give an undefined. But will be nice to have a state which is initialised to `['']` - array with an empty string. token seems to be part of an object. I am wondering if it is garbage collected :) Maybe, a console.log can help test for it. https://stackoverflow.com/questions/28839652/will-console-log-prevent-garbage-collection – vijayst May 31 '17 at 11:13
  • @vijayst Ok so I've manged to ascertain that if a hard browser reload of any of the Route paths is done, the store gets destroyed and `state === undefined` in tokenDetails.js gets triggered. thus resetting state back to `state = {}`. How do I prevent this from happening? – TheoG May 31 '17 at 19:29
  • Store the token in localStorage instead of Redux. – vijayst May 31 '17 at 22:28

0 Answers0