8

I build a React and now I am trying to migrate from React Router dom to Next.js. I made the major changes and refactored the code in; (pages/routes and store.js) but then I got this error "ReferenceError: localStorage is not defined".

  19 | const initialState = {
> 20 | access: localStorage.getItem('access'),
     |        ^
  21 | refresh: localStorage.getItem('refresh'),
  22 | isAuthenticated: null,
  23 | user: null

could you please help me through this?

reducers/auth.js :

import {
    LOGIN_SUCCESS,
    LOGIN_FAIL,
    SIGNUP_SUCCESS,
    SIGNUP_FAIL,
    ACTIVATION_SUCCESS,
    ACTIVATION_FAIL,
    USER_LOADED_SUCCESS,
    USER_LOADED_FAIL,
    AUTHENTICATED_SUCCESS,
    AUTHENTICATED_FAIL,
    PASSWORD_RESET_SUCCESS,
    PASSWORD_RESET_FAIL,
    PASSWORD_RESET_CONFIRM_SUCCESS,
    PASSWORD_RESET_CONFIRM_FAIL,
    LOGOUT
} from '../actions/types';

const initialState = {
    access: localStorage.getItem('access'),
    refresh: localStorage.getItem('refresh'),
    isAuthenticated: null,
    user: null
};

export default function (state = initialState, action) {
    const { type, payload } = action;

    switch(type) {
        case AUTHENTICATED_SUCCESS:
            return {
                ...state,
                isAuthenticated: true
            }
        case LOGIN_SUCCESS:
            localStorage.setItem('access', payload.access);
            localStorage.setItem('refresh', payload.refresh);
            return {
                ...state,
                isAuthenticated: true,
                access: payload.access,
                refresh: payload.refresh
            }
        case USER_LOADED_SUCCESS:
            return {
                ...state,
                user: payload
            }
        case SIGNUP_SUCCESS:
            return {
                ...state,
                isAuthenticated: false
            }
        case AUTHENTICATED_FAIL:
            return {
                ...state,
                isAuthenticated: false
            }
        case USER_LOADED_FAIL:
            return {
                ...state,
                user: null
            }
        case LOGIN_FAIL:
        case SIGNUP_FAIL:
        case LOGOUT:
            localStorage.removeItem('access');
            localStorage.removeItem('refresh');
            return {
                ...state,
                access: null,
                refresh: null,
                isAuthenticated: false,
                user: null
            }
        case PASSWORD_RESET_SUCCESS:
        case PASSWORD_RESET_FAIL:
        case ACTIVATION_SUCCESS:
        case ACTIVATION_FAIL:
        case PASSWORD_RESET_CONFIRM_SUCCESS:
        case PASSWORD_RESET_CONFIRM_FAIL:
            return {
                ...state
            }

        default:
            return state
    }
};

src/store.js

import { useMemo } from 'react';
import { applyMiddleware } from 'redux';
import { legacy_createStore as createStore } from 'redux';
import { composeWithDevTools } from 'redux-devtools-extension';
import thunkMiddleware from 'redux-thunk';
import reducers from './reducers';

let store;

function initStore(initialState) {
  return createStore(
    reducers,
    initialState,
    composeWithDevTools(applyMiddleware(thunkMiddleware))
  );
};

export const initializeStore = (preloadedState) => {
  let _store = store ?? initStore(preloadedState);

  // After navigating to a page with an initial Redux state, merge that state
  // with the current state in the store, and create a new store
  if (preloadedState && store) {
    _store = initStore({
      ...store.getState(),
      ...preloadedState,
    })
    // Reset the current store
    store = undefined;
  }

  // For SSG and SSR always create a new store
  if (typeof window === 'undefined') return _store;
  // Create the store once in the client
  if (!store) store = _store;

  return _store;
}

export function useStore(initialState) {
  const store = useMemo(() => initializeStore(initialState), [initialState]);
  return store;
}

Thank you in advance

Moammer
  • 139
  • 1
  • 2
  • 11

1 Answers1

16

NextJs using server side render, the window object is not defined there. The thing to do is to check the existence of the window object, or preferably using it only where it is defined, in a useEffect hook for example, the hook executing client side.

You could do something like :

const initialState = {
    access: typeof window !== "undefined" ? window.localStorage.getItem('access') : false,
    refresh: typeof window !== "undefined" ?  window.localStorage.getItem('refresh') : false,
    isAuthenticated: null,
    user: null
};
JeanJacquesGourdin
  • 1,496
  • 5
  • 25
  • Hi Jean, Thanks for your answer. Now I'm getting "ReferenceError: window is not defined" – Moammer Sep 26 '22 at 12:54
  • @Moammer That's a step forward ! Joke aside, I edited the answer, please tell me if it's still undefined – JeanJacquesGourdin Sep 26 '22 at 13:32
  • Still showing the same message ; "ReferenceError: window is not defined" ___________________________ 19 | const initialState = { > 20 | access: typeof window != undefined ? window.localStorage.getItem('access') : false, | ^ 21 | refresh: typeof window != undefined ? window.localStorage.getItem('refresh') : false, 22 | isAuthenticated: null, 23 | user: null – Moammer Sep 27 '22 at 07:19
  • Ok I edited again with a strong type check eg "!==" instead of "!=". It should work now, if not, no idea how to debug – JeanJacquesGourdin Sep 27 '22 at 07:41
  • Hey Jean, I tried that already and it didn't work. but, thanks for your support – Moammer Sep 27 '22 at 07:50
  • Hey Jean, I tried that already and it didn't work. but, thanks for your support – Moammer Sep 27 '22 at 07:51
  • I sorry @Moammer, cannot help further. Probably comes from redux being redux.. Maybe check https://stackoverflow.com/questions/71781864/redux-store-nextjs-config-throws-window-not-defined Hope it helps – JeanJacquesGourdin Sep 27 '22 at 08:01
  • 1
    Hey Jean, Many thanks. Actually, your code is the solution. After checking store.js I added '' to undefined to become 'undefined' and all works gooooD! Many thanks buddy for your support – Moammer Sep 27 '22 at 08:10
  • I edited the answer to match what you said worked. Have a nice life my friend ! – JeanJacquesGourdin Sep 27 '22 at 08:24
  • I have done this. But NextJs complains on build (Prerendering issue.). FYI, I set `output` to `export`. – Hamid Mayeli Jul 07 '23 at 14:06