lost auth state when page refresh in reactjs hooks - reactjs

When i login with valid credentials server send JWT to browser i store this JWT in localstore page redirect to home page everything works fine and in home page i have loadUser function which send request to server to get the user details of valid user but when i refresh the page it home page never execute because auth state returns to false and page redirect from home to login page
This is App.js
import React, { Fragment } from "react";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import Navbar from "./components/layout/Navbar";
import Home from "./components/pages/Home";
import Login from "./components/auth/Login";
import PrivateRoute from "./components/routing/PrivateRoute";
import "./App.css";
const App = () => {
return (
<AuthState>
<Router>
<Fragment>
<Navbar />
<div className="container">
<Alerts />
<Switch>
<PrivateRoute exact path="/" component={Home} />
<Route exact path="/login" component={Login} />
</Switch>
</div>
</Fragment>
</Router>
</AuthState>
);
};
export default App;
This is my authsate code from where my state changes after successful login
import React, { useReducer } from "react";
import axios from "axios";
import AuthContext from "./authContext";
import authReducer from "./authReducer";
import {
USER_LOADED,
AUTH_ERROR,
LOGIN_SUCCESS,
LOGIN_FAIL,
} from "../types";
const AuthState = props => {
const initialState = {
isAuthenticated: null,
user: null,
};
const [state, dispatch] = useReducer(authReducer, initialState);
// Load User
const loadUser = async () => {
if (localStorage.token) {
setAuthToken(localStorage.token);
}
try {
const res = await axios.get("/api/auth");
dispatch({ type: USER_LOADED, payload: res.data });
} catch (err) {
dispatch({ type: AUTH_ERROR });
}
};
// Login User
const login = async formData => {
const config = {
headers: {
"Content-Type": "application/json"
}
};
try {
const res = await axios.post("api/auth", formData, config);
dispatch({
type: LOGIN_SUCCESS,
payload: res.data
});
loadUser();
} catch (err) {
dispatch({
type: LOGIN_FAIL,
payload: err.response.data.msg
});
}
};
return (
<AuthContext.Provider
value={{
isAuthenticated: state.isAuthenticated,
user: state.user,
loadUser,
login,
}}
>
{props.children}
</AuthContext.Provider>
);
};
export default AuthState;
This is reducer code authReducer.js
import {
USER_LOADED,
AUTH_ERROR,
LOGIN_SUCCESS,
LOGIN_FAIL,
} from "../types";
export default (state, action) => {
switch (action.type) {
case USER_LOADED:
return {
...state,
isAuthenticated: true,
user: action.payload
};
case LOGIN_SUCCESS:
localStorage.setItem("token", action.payload.token);
return {
...state,
isAuthenticated: true
};
case AUTH_ERROR:
case LOGIN_FAIL:
localStorage.removeItem("token");
return {
...state,
isAuthenticated: false,
user: null,
};
default:
return state;
}
};
This is private route
import React, { useContext } from "react";
import { Route, Redirect } from "react-router-dom";
import AuthContext from "../../context/auth/authContext";
const PrivateRoute = ({ component: Component, ...rest }) => {
const authContext = useContext(AuthContext);
const { isAuthenticated, loading } = authContext;
return (
<Route
{...rest}
render={props =>
!isAuthenticated && !loading ? (
<Redirect to="/login" />
) : (
<Component {...props} />
)
}
/>
);
};
export default PrivateRoute;

That's to be expected.
If you want to persist the token you should save it in localStorage or a cookie.
Then, you should check for the token existence and validity in componentDidMount or in an useEffect (with a void dependency array) if you are using hooks.
It'd be nice if you could show us where you are making AJAX requests because if, for example, you are using Axios you can encapsulate this logic in a request interceptor.

Probably the JSON web token which is used for user authentication/authorization. Can you give us more information about this?

Related

While using Multiple context in react hooks getting blank

I am new to context api. I am trying to use multiple context.
I have created a UserContext and GlobalContext which I'm trying to use in the app.js but as soon as I put UserContext I get the blank page.
here is my app.js
import { useEffect } from 'react';
import { GlobalProvider } from './context/GlobalState'
import './App.css'
import { Home } from './pages/Home';
import { Login } from './pages/Login';
import { Register } from './pages/Register';
import axios from 'axios';
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import { UserProvider } from './context/UserContext';
const App = () => {
return (
<UserProvider>
<GlobalProvider>
<BrowserRouter>
<Routes>
<Route path='/login' element={<Login />} />
<Route path='/register' element={<Register />} />
<Route path='/home' element={<Home />} />
</Routes>
</BrowserRouter>
</GlobalProvider>
</UserProvider>
)
}
export default App;
Here is my UserContext.js
import axios from "axios";
import { createContext, useReducer } from "react";
import { userReducer } from "./AppReducer";
// Initial State
const initialState = {
isAuthenticated: false
}
// Creating Context
export const UserContext = createContext(initialState)
UserContext.displayName = "UserContext"
// Creating Provider
export const UserProvider = ({ childern }) => {
const [state, dispatch] = useReducer(userReducer, initialState);
// Actions
async function authenticate(user) {
try {
const config = {
Headers: {
'Content-Type': 'application/json'
}
}
const hasToken = res.data.token === undefined ? false : res.data.token;
dispatch({
type: 'AUTHENTICATE_USER',
payload: hasToken
})
const res = await axios.post('https://localhost:7188/api/user/authenticate', user, config);
if (res.data.token !== undefined) {
console.log("No token")
}
else {
console.log(res.data.token);
}
localStorage.setItem('jwt', res.data.token);
console.log(localStorage.getItem('jwt'));
} catch (error) {
console.log(error.response);
}
}
return (
<UserContext.Provider value={
{
isAuthenticated: state.isAuthenticated,
authenticate
}
}>
{childern}
</UserContext.Provider>
)
}
Here is AppReducer.js
export const userReducer = (state, action) => {
switch (action.type) {
case 'AUTHENTICATE_USER':
return {
...state,
isAuthenticated : action.payload
}
default:
return state;
}
}
When I start the server I'm getting blank page

Change in redux store is not performing re-render wherever that state is being used

I am trying to get the token from the api's provided by spotify everything here works as expected except one. When my reducer updates my authentication state it doesn't perform the re-render in my component where ever auth token is used. It still showing undefined after updating the store but when i refresh the login url it shows changes that were previously made.
here is my login.jsx
import { generateAuthorizeUrl, extractUrlParams } from "../utils";
import React, { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { scopes } from "../spotify";
import { signIn } from "../actions";
const Login = (props) => {
const { refreshToken, loading, error } = useSelector((state) => state.auth);
console.log(refreshToken, loading, error);
const dispatch = useDispatch();
const onClickHandler = function (e) {
e.preventDefault();
var a = document.createElement("a");
a.href = generateAuthorizeUrl()(scopes);
a.click();
};
useEffect(() => {
if (window.location.search.includes("code=") && !refreshToken) {
var { code, state } = extractUrlParams();
dispatch(signIn(code, state));
}
}, [dispatch, refreshToken]);
return (
<div>
{props.refreshToken}
<button onClick={onClickHandler}>login with spotify</button>
</div>
);
};
export default Login;
here is my authAction to perform when spotify redirect me with code and state parameter in url
import axios from "axios";
import {
USER_SIGNIN_FAILURE,
USER_SIGNIN_REQUEST,
USER_SIGNIN_SUCCESS,
} from "../contants/AuthConstants";
import { Base64, getItem } from "../utils";
// DISPATCH DATA FOR MAKING REQUEST STATE
const signInRequest = () => ({ type: USER_SIGNIN_REQUEST });
// DISPATCH DATA FOR SUCCESS AND FAILURE REQUEST
const signInResponse = (error = false, data) => ({
type: error ? USER_SIGNIN_FAILURE : USER_SIGNIN_SUCCESS,
payload: data,
});
// SIGN IN ACTION TO BE DISPATCHED TO REDUCER FOR LOGIN STUFF
export const signIn = (code, state) => async (dispatch, getState) => {
dispatch(signInRequest());
let _state = getItem(process.env.REACT_APP_STATE_KEY);
// CHECK IF STATE IS NULL OR PROVIDED STATE DOES NOT MATCHES STATE STORED IN LOCALSTORAGE
if (!state || state !== _state) {
// IF TRUE OUR AUTHORAIZATION FAILS
dispatch(signInResponse(true, "state mismatched, Authorization failed"));
} else {
// ELSE MAKE REQUEST TO TOKEN URI FOR ACCEPTION TOKEN
await axios({
url: process.env.REACT_APP_TOKEN_URI,
method: "POST",
data: new URLSearchParams({
code: code,
redirect_uri: process.env.REACT_APP_REDIRECT_URI,
grant_type: "authorization_code",
}).toString(),
headers: {
Authorization: `Basic ${Base64.encode(
`${process.env.REACT_APP_CLIENT_ID}:${process.env.REACT_APP_CLIENT_SECRET}`
)}`,
"Content-Type": "application/x-www-form-urlencoded",
},
})
.then((res) => {
dispatch(signInResponse(false, res.data));
})
.catch((error) => dispatch(signInResponse(true, error.message)));
}
};
here is the authReducer
import {
USER_SIGNIN_FAILURE,
USER_SIGNIN_REQUEST,
USER_SIGNIN_SUCCESS,
} from "../contants/AuthConstants";
import { setItem } from "../utils";
const AuthReducer = (state = { loading: false, error: "" }, action) => {
switch (action.type) {
case USER_SIGNIN_REQUEST:
return { ...state, loading: true };
case USER_SIGNIN_SUCCESS:
let auth = {
refreshToken: action.payload.refresh_token,
accessToken: action.payload.access_token,
expiresIn: new Date().getTime() + 3540 * 1000,
tokenType: action.payload.token_type,
};
setItem(process.env.REACT_APP_TOKEN_KEY)(JSON.stringify(auth));
return {
...state,
loading: false,
auth: auth,
error: null,
};
case USER_SIGNIN_FAILURE:
return { ...state, loading: false, error: action.payload, auth: {} };
default:
return state;
}
};
export { AuthReducer };
here is store.js
import { applyMiddleware, combineReducers, compose, createStore } from "redux";
import thunk from "redux-thunk";
import { AuthReducer } from "../reducers/AuthReducers";
import { getItem } from "../utils";
const initialState = {
auth: getItem(process.env.REACT_APP_TOKEN_KEY)
? JSON.parse(getItem(process.env.REACT_APP_TOKEN_KEY))
: {},
};
const rootReducer = combineReducers({
auth: AuthReducer,
});
const composeEnhancer = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(
rootReducer,
initialState,
composeEnhancer(applyMiddleware(thunk))
);
export default store;
Here is Login Component parent Container
import { BrowserRouter, Routes, Route } from "react-router-dom";
import styled from "styled-components";
import Privateroute from "./route/PrivateRoute";
import { Home, Login } from "./screens";
function App() {
return (
<BrowserRouter>
<AppContainer>
<Routes>
<Route path="/auth/login" element={<Login />} />
<Route
path="/"
element={
<Privateroute>
<Home />
</Privateroute>
}
></Route>
</Routes>
</AppContainer>
</BrowserRouter>
);
}
const AppContainer = styled.div``;
export default App;
and last here is my private route component
import React from "react";
import { useSelector } from "react-redux";
import { Navigate } from "react-router-dom";
const Privateroute = (props) => {
const token = useSelector((state) => state.auth.refreshToken);
return token ? props.children : <Navigate to="/auth/login" />;
};
export default Privateroute;
You need to wrap your code with <Provider store={store}></Provider>

React Router - When unauthenticated refreshing on plain route pages redirects me to index page

When a user is authenticated, I can refresh the page and access all the routes through the website or by entering/refreshing the URL. However, when the user is unauthenticated, although the routing through the website works well, refreshing the URL even on plain route pages (non-private) redirects me to index (main page).
I have used this as the template of my react app and this for adding authentication to my react app. I have tried these two guides seperately and both work well but somehow in my react app their combination leads to the issue I described above.
Below is the code for my app routes:
import React, { Component, lazy, Suspense} from 'react';
import { Switch, Route, Redirect } from 'react-router-dom';
import Spinner from '../app/shared/Spinner';
const MainIndex = lazy(() => import( "./mainpage/Index"));
const TermsIndex = lazy(() => import( "./mainpage/Terms"));
const Dashboardmain = lazy(() => import( "./dashboard/Dashboardmain"));
const Login = lazy(() => import( "./user-pages/Login"));
const Register = lazy(() => import( "./user-pages/Register"));
class AppRoutes extends Component {
render () {
return (
<Suspense fallback={<Spinner/>}>
<Switch>
<Route exact path="/login" component={ Login } />
<Route exact path="/index" component={ MainIndex } />
<Route exact path="/terms" component={ TermsIndex } />
<PrivateRoute exact path="/internal/dashboard" component={ Dashboardmain } />
<Route exact path="/register" component={ Register } />
</Switch>
</Suspense>
);
}
}
export default AppRoutes;
My app pages look like this - the FullPageLayout is to check if header, footer or sidebar should be added for the page or not:
import React, { Component } from 'react';
import AppRoutes from './AppRoutes';
import Navbar from './shared/Navbar';
import Sidebar from './shared/Sidebar';
import Footer from './shared/Footer';
import { withRouter } from 'react-router-dom';
class AppPages extends Component {
state = {}
componentDidMount() {
this.onRouteChanged();
}
render () {
let navbarComponent = !this.state.isFullPageLayout ? <Navbar/> : '';
let sidebarComponent = !this.state.isFullPageLayout ? <Sidebar/> : '';
let footerComponent = !this.state.isFullPageLayout ? <Footer/> : '';
return (
<div className="container-scroller">
{ sidebarComponent }
<div className="container-fluid page-body-wrapper">
{ navbarComponent }
<div className="main-panel">
<div className="content-wrapper">
<AppRoutes/>
</div>
{ footerComponent }
</div>
</div>
</div>
);
}
componentDidUpdate(prevProps) {
if (this.props.location.pathname !== prevProps.location.pathname) {
this.onRouteChanged();
}
}
onRouteChanged() {
const containment = [];
const fullPageLayoutRoutes = ['/login', '/register',
'/index', '/terms'];
const body = document.querySelector('body');
body.classList.remove('rtl')
for (var i = 0; i < fullPageLayoutRoutes.length; i++) {
containment[containment.length] = this.props.location.pathname.toLowerCase().includes(fullPageLayoutRoutes[i])
}
if (containment.includes(true)) {
this.setState({isFullPageLayout: true})
document.querySelector('.page-body-wrapper').classList.add('full-page-wrapper');
} else {
this.setState({isFullPageLayout: false})
document.querySelector('.page-body-wrapper').classList.remove('full-page-wrapper');
}
}
}
export default withRouter(AppPages);
And my app is as follows:
import React, { Component } from 'react';
import { BrowserRouter } from 'react-router-dom';
import './App.scss';
import { Provider } from "react-redux";
import jwt_decode from "jwt-decode";
import setAuthToken from "../utils/setAuthToken";
import { setCurrentUser, logoutUser } from "../actions/authActions";
import store from "../store";
import AppPages from './AppPages';
// Check for token to keep user logged in
if (localStorage.jwtToken) {
// Set auth token header auth
const token = localStorage.jwtToken;
setAuthToken(token);
// Decode token and get user info and exp
const decoded = jwt_decode(token);
// Set user and isAuthenticated
store.dispatch(setCurrentUser(decoded));
// Check for expired token
const currentTime = Date.now() / 1000; // to get in milliseconds
if (decoded.exp < currentTime) {
// Logout user
store.dispatch(logoutUser());
// Redirect to login
window.location.href = "/login";
}
}
class App extends Component {
render () {
return (
<Provider store={store}>
<BrowserRouter>
<AppPages/>
</BrowserRouter>
</Provider>
);
}
}
export default App;
I tried debugging the issue by changing/simplifying things in the router or app part but I don't think the problem is here. I think the problem is somewhere within the reducers or actions.
My store is defined as follows:
import { createStore, applyMiddleware, compose } from "redux";
import thunk from "redux-thunk";
import rootReducer from "./reducers";
const initialState = {};
const middleware = [thunk];
const store = createStore(
rootReducer,
initialState,
compose(
applyMiddleware(...middleware),
(window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ &&
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__()) ||
compose
)
);
export default store;
My authReducer is defined as:
import { SET_CURRENT_USER, USER_LOADING } from "../actions/types";
const isEmpty = require("is-empty");
const initialState = {
isAuthenticated: false,
user: {},
loading: false
};
export default function(state = initialState, action) {
switch (action.type) {
case SET_CURRENT_USER:
return {
...state,
isAuthenticated: !isEmpty(action.payload),
user: action.payload
};
case USER_LOADING:
return {
...state,
loading: true
};
default:
return state;
}
}
My authAction is defined as:
import axios from "axios";
import setAuthToken from "../utils/setAuthToken";
import jwt_decode from "jwt-decode";
import { GET_ERRORS, SET_CURRENT_USER, USER_LOADING } from "./types";
// Register User
export const registerUser = (userData, history) => dispatch => {
axios
.post("/api/users/register", userData)
.then(res => history.push("/login")) // re-direct to login on successful register
.catch(err =>
dispatch({
type: GET_ERRORS,
payload: err.response.data
})
);
};
// Login - get user token
export const loginUser = userData => dispatch => {
axios
.post("/api/users/login", userData)
.then(res => {
// Save to localStorage
// Set token to localStorage
const { token } = res.data;
localStorage.setItem("jwtToken", token);
// Set token to Auth header
setAuthToken(token);
// Decode token to get user data
const decoded = jwt_decode(token);
// Set current user
dispatch(setCurrentUser(decoded));
})
.catch(err =>
dispatch({
type: GET_ERRORS,
payload: err.response.data
})
);
};
// Set logged in user
export const setCurrentUser = decoded => {
return {
type: SET_CURRENT_USER,
payload: decoded
};
};
// User loading
export const setUserLoading = () => {
return {
type: USER_LOADING
};
};
// Log user out
export const logoutUser = () => dispatch => {
// Remove token from local storage
localStorage.removeItem("jwtToken");
// Remove auth header for future requests
setAuthToken(false);
// Set current user to empty object {} which will set isAuthenticated to false
dispatch(setCurrentUser({}));
};
It's something to do with the order of execution. The redux state gets erased when you refresh so you need the store.dispatch(setCurrentUser(decoded)) to get called before the PrivateRoute tries to render. It's not obvious to me precisely where it's going wrong because the if (localStorage.jwtToken) { block is not async, though the dispatch might be?
I would recommend setting the initialState in authReducer to isAuthenticated: null and update to either true or false once you've examined the token. Right now your PrivateRoute only knows two states: authenticated and unauthenticated. We need it to understand a third which is "I don't know yet". In your PrivateRoute you would render nothing or a loading spinner while isAutheticated is null. Don't render the Redirect until you have a definite false.
So after some debugging, I realised that my problem is coming from AppPages and the line with { navbarComponent }. This navbar is used with the PrivateRoute and requires the user to be defined. When the user is unauthenticated, although this will not technically render for plain routes, it is still processed and inside this navbar is a condition that if the user is undefined, will return to the index page.

Private Route with Redux and react router

I have a simple app with auth and private route, I want to get data from the server if the user has token, the back end is ready and works fine, and I log in I have data in redux about the user, but I don't know how to handle with refresh page, where should I do dispatch to call action? if I do it in privateRoute.js, it works strange I want to call server ones, but I did it 3-4 times.
Here are my components without calling sessionActions, sessionActions should update loggedIn and the user would go to /login pages
PrivateRoute
import React, { useState, useEffect } from 'react';
import { Route, Redirect } from 'react-router-dom';
import PropTypes from 'prop-types';
import sessionAction from '../store/actions/sessionAction';
const PrivateRoute = ({ component: Component, ...rest }) => {
const { path, dispatch, loggedIn } = rest;
});
return (
<Route
path={path}
render={(props) => (loggedIn ? <Component {...props} />
<Component {...props}/>
: (<Redirect to="/login" />))}
/>
);
};
PrivateRoute.propTypes = {
component: PropTypes.func.isRequired,
};
export default PrivateRoute;
sessionAction
const sessionAction = (path) => (dispatch) => {
return sessionServices(path)
.then((response) => {
console.log(response);
const { data } = response;
if (!data.error) {
dispatch(success(data));
}
dispatch(failure(data.error.text));
})
.catch((error) => error);
};
sessionService
import axios from 'axios';
axios.defaults.withCredentials = true;
const sessionServices = (path) => axios({
method: 'post',
url: `http://localhost:4000/api/pages${path}`,
})
.then((response) => response)
.catch((error) => console.log(error));
export default sessionServices;
You must dispatch the actions to fetch user data from the server in your App component which is the top-level component. Also, maintain a loading state in the reducer to render a Loader until the user data is fetched.
const App = props => {
useEffect(() {
this.props.sessionActions('/session')
}, []);
if(this.state.isLoading) return <Loader />;
const { loggedIn, user } = this.props;
return (
<Router>
{/* Your Private routes and other routes here */}
</Router>
)
}
const mapStateToProps = (state) => {
return {
isLoading: state.auth.isLoading,
user: state.auth.user,
loggedIn: state.auth.loggedIn
}
}
export default connect(mapStateToProps, { sessionAction })(App);

TypeError: Cannot read property 'profile' of undefined

I'm just starting to learn Redux and I've run into this error and can't seem to figure out where I've gone wrong. In my profileReducer.js file, I set an initialState to have profile be equal to null. Somewhere along the line, something fails and if I console.log(this.state) profile is undefined.
The error:
TypeError: Cannot read property 'profile' of undefined
Dashboard.render
src/components/dashboard/Dashboard.js:11
8 | this.props.getCurrentProfile();
9 | }
10 |
> 11 | render() {
12 | const { user } = this.props.auth;
13 | const { profile, loading } = this.props.profile;
14 |
profileReducer.js
import {
GET_PROFILE,
PROFILE_LOADING,
CLEAR_CURRENT_PROFILE
} from "../actions/types";
const initialState = {
profile: null,
profiles: null,
loading: false
};
export default function(state = initialState, action) {
switch (action.type) {
case PROFILE_LOADING:
return {
...state,
loading: true
};
case GET_PROFILE:
return {
...state,
profile: action.payload,
loading: false
};
case CLEAR_CURRENT_PROFILE:
return {
...state,
profile: null
};
default:
return state;
}
}
profileActions.js
import axios from "axios";
import {
GET_PROFILE,
PROFILE_LOADING,
CLEAR_CURRENT_PROFILE,
GET_ERRORS
} from "./types";
// Get current profile
export const getCurrentProfile = () => dispatch => {
dispatch(setProfileLoading());
axios
.get("/api/profile")
.then(res =>
dispatch({
type: GET_PROFILE,
payload: res.data
})
)
.catch(err =>
dispatch({
type: GET_PROFILE,
payload: {}
})
);
};
// Create Profile
export const createProfile = (profileData, history) => dispatch => {
axios
.post("/api/profile", profileData)
.then(res => history.push("/dashboard"))
.catch(err =>
dispatch({
type: GET_ERRORS,
payload: err.response.data
})
);
};
// Profile loading
export const setProfileLoading = () => {
return {
type: PROFILE_LOADING
};
};
// Clear profile
export const clearCurrentProfile = () => {
return {
type: CLEAR_CURRENT_PROFILE
};
};
Dashboard.js
import React, { Component } from "react";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import { getCurrentProfile } from "../../actions/profileActions";
class Dashboard extends Component {
componentDidMount() {
this.props.getCurrentProfile();
}
render() {
const { user } = this.props.auth;
const { profile, loading } = this.props.profile;
let dashboardContent;
if (profile === null || loading) {
dashboardContent = <h4>Loading</h4>;
} else {
dashboardContent = <h1>Hello</h1>;
}
return (
<div className="dashboard">
<div className="container">
<div className="row">
<div className="col-md-12">
<h1 className="display-4">Dashboard</h1>
{dashboardContent}
</div>
</div>
</div>
</div>
);
}
}
Dashboard.propTypes = {
getCurrentProfile: PropTypes.func.isRequired,
auth: PropTypes.object.isRequired,
profile: PropTypes.object.isRequired
};
const mapStateToProps = state => ({
profile: state.profile,
auth: state.auth
});
export default connect(
mapStateToProps,
{ getCurrentProfile }
)(Dashboard);
App.js
import React, { Component } from "react";
import "./App.css";
import Navbar from "./components/layout/Navbar";
import Footer from "./components/layout/Footer";
import Landing from "./components/layout/Landing";
import Login from "./components/auth/Login";
import Register from "./components/auth/Register";
import { BrowserRouter as Router, Route } from "react-router-dom";
import jwt_decode from "jwt-decode";
import setAuthToken from "./utils/setAuthToken";
import { setCurrentUser, logoutUser } from "./actions/authActions";
import { clearCurrentProfile } from "./actions/profileActions";
import { Provider } from "react-redux";
import store from "./store";
import Dashboard from "./components/dashboard/Dashboard";
// Check for token
if (localStorage.jwtToken) {
// Set auth token header auth
setAuthToken(localStorage.jwtToken);
// Decode token and get user info and exp
const decoded = jwt_decode(localStorage.jwtToken);
// Set user and isAuthenticated
store.dispatch(setCurrentUser(decoded));
// Check for expired token
const currentTime = Date.now() / 1000;
if (decoded.exp < currentTime) {
// Logout user
store.dispatch(logoutUser());
// clear current profile
store.dispatch(clearCurrentProfile());
// Redirect to login
window.location.href = "/login";
}
}
class App extends Component {
render() {
return (
<Provider store={store}>
<Router>
<div className="App">
<Navbar />
<Route exact path="/" component={Landing} />
<div className="container">
<Route exact path="/register" component={Register} />
<Route exact path="/login" component={Login} />
<Route exact path="/dashboard" component={Dashboard} />
</div>
<Footer />
</div>
</Router>
</Provider>
);
}
}
export default App;
store.js
import { createStore, applyMiddleware, compose } from "redux";
import thunk from "redux-thunk";
import rootReducer from "./reducers";
const initialState = {};
const middleware = [thunk];
const store = createStore(
rootReducer,
initialState,
compose(
applyMiddleware(...middleware),
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
)
);
export default store;
index.js
export default combineReducers({
auth: authReducer,
errors: errorReducer,
profie: profileReducer
});
A few hours later.....profie should be profile =)

Resources