I'm working on an app with a login page and the rest of the pages of the app (should be logged in to view). I'm using react-boilerplate. From this example, I edited my asyncInjectors.js file to have redirectToLogin and redirectToDashboard methods:
//asyncInjectors.js
export function redirectToLogin(store) {
return (nextState, replaceState) => {
const isAuthenticated = store.getState().get('app').get('isAuthenticated');
if (!isAuthenticated) {
replaceState({
pathname: '/login',
state: {
nextPathname: nextState.location.pathname,
},
});
}
};
}
export function redirectToDashboard(store) {
return (nextState, replaceState) => {
const isAuthenticated = store.getState().get('app').get('isAuthenticated');
if (isAuthenticated) {
replaceState('/');
}
}
}
Then I just set the redirectToLogin as the onEnter of the pages and redirectToDashboard for the login page.
It works fine but when the page is refreshed (F5) when logged in, the login page renders briefly and then renders the actual page. The login page just dispatches an authenticate action in componentWillMount and then redirects in componentDidUpdate:
//login.js
componentWillMount() {
this.props.dispatch(authenticate());
}
componentDidUpdate(prevProps, prevState) {
if (this.props.isAuthenticated) {
const nextPathname = prevProps.location.state ? prevProps.location.state.nextPathname : '/';
browserHistory.push(nextPathname);
}
}
The container for the pages also has the same componentWillMount code. Not sure if it's because of the sagas but here's the code:
//sagas.js
export function* login({ user, password }) {
try {
const token = yield call(app.authenticate, {
strategy: 'local',
user,
password,
});
return token;
} catch (error) {
return onError(error);
}
}
// For page refresh after logging in
export function* authenticate() {
try {
const token = yield call(app.authenticate);
return token;
} catch (error) {
return onError(error);
}
}
export function* logout() {
try {
const response = yield call(app.logout);
return response;
} catch (error) {
return onError(error);
}
}
export function* loginFlow() {
while (true) {
const request = yield take(LOGIN_REQUEST);
const winner = yield race({
auth: call(login, request.data),
logout: take(LOGOUT_REQUEST),
});
if (winner.auth && winner.auth.accessToken) {
yield put(actions.setAuthState(true));
}
}
}
export function* logoutFlow() {
while (true) {
yield take(LOGOUT_REQUEST);
yield put(actions.setAuthState(false));
yield call(logout);
browserHistory.push('/login');
}
}
export function* authenticateFlow() {
while (true) {
yield take(AUTHENTICATE);
const response = yield call(authenticate);
if (response && response.accessToken) {
yield put(actions.setAuthState(true));
}
}
}
export default [
loginFlow,
logoutFlow,
authenticateFlow,
];
How do I get rid of the flashing login page?
EDIT: When I tried gouroujo's answer, I couldn't logout.
//asyncInjectors.js
import jwtDecode from 'jwt-decode';
export function redirectToLogin(store) {
return (nextState, replaceState, callback) => {
const token = localStorage.token;
if (token) {
const jwt = jwtDecode(token);
if (jwt.exp <= (new Date().getTime() / 1000)) {
store.dispatch(actions.setAuthState(false));
replaceState({
pathname: '/login',
state: {
nextPathname: nextState.location.pathname,
},
});
}
}
store.dispatch(actions.setAuthState(true));
callback();
};
}
When I hit refresh, the login page doesn't show but now I can't log out.