在Next.js中解决ReferenceError: localStorage未定义的问题

13

我建了一个 React 项目,现在正在尝试从 React Router dom 迁移到 Next.js。我进行了重大更改并重新设计代码(在 pages/routes 和 store.js 中),但是之后出现了错误“ReferenceError: localStorage is not defined”。

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

请问您需要帮忙翻译什么内容?

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;
}

感谢您的提前帮助。
1个回答

22

使用服务器端渲染的 Next.js,其中 window 对象在该处未定义。需要做的是检查 window 对象是否存在,或者最好仅在其定义的地方使用(例如,在 useEffect 钩子中,在客户端执行的钩子)。

你可以这样做:

const initialState = {
    access: typeof window !== "undefined" ? window.localStorage.getItem('access') : false,
    refresh: typeof window !== "undefined" ?  window.localStorage.getItem('refresh') : false,
    isAuthenticated: null,
    user: null
};

1
嗨,Jean,谢谢你的回答。现在我收到了“ReferenceError: window is not defined”的错误提示。 - Moammer
@Moammer 这是一个进步!开玩笑的,我编辑了答案,请告诉我它是否仍然未定义。 - JeanJacquesGourdin
好的,我再次进行了编辑,使用了强类型检查,例如“!==”而不是“!=”。现在应该能正常工作了,如果还有问题,我也不知道如何调试了。 - JeanJacquesGourdin
嗨,Jean,我已经尝试过了,但是它没有起作用。不过,感谢你的支持。 - Moammer
1
嗨,Jean,非常感谢。实际上,你的代码就是解决方案。在检查store.js后,我将''添加到undefined中变成了'undefined',一切都很好!非常感谢你的支持,伙计。 - Moammer
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接