programing

페이지 새로 고침 시 NextJS에서 Redex 상태를 올바르게 수산화하는 방법

prostudy 2022. 4. 3. 19:50
반응형

페이지 새로 고침 시 NextJS에서 Redex 상태를 올바르게 수산화하는 방법

앱 다시 로드/페이지 새로 고침 시 로컬 스토리지에서 사용자 데이터에 수분이 공급되는 문제가 발생함.

내 프로젝트에서 프런트엔드와 지원 라이브러리에 NextJS를 사용하고 있다.redux-toolkit애플리케이션 전체에서 환원 관리를 위해next-redux-wrapper포장된 페이지들에 대한 국가수화를 위해.

사용자가 로그인할 수 있으며, 이 경우 다음 항목을 저장한다.isLoggedIn로컬 저장소와 환원 상태의 부울.에 따라isLoggedIn부울 값 I 변경Navbar구성요소 스타일(더)Navbar에 직접 포함되다_app.tsx).

사용자가 페이지를 새로 고칠 때isLoggedIn부울은 상태로 로드되지 않고 로컬 저장소에 있다.

과거에 나는 사용해 왔다.redux-persist하지만 나는 그것을 사용하지 않기로 선택했다. 왜냐하면 그 이유는PersistGateSSR 아이디어와 충돌하는 저장소에서 지속 데이터를 가져올 때까지 UI 렌더링을 차단하고 있었다.

현재, 나는 다음 것을 가지고 있다.isLoggedIn로딩 문제 해결 방법App.getInitialProps에 있어서의 방법._app.ts그리고 나서 그 결과 로부터 수분을 공급하게 된다.next-redux-persist로드된 각 페이지와 모든 페이지에 대해 호출되지만, 이것은 또 다른 문제를 야기한다: 모든 페이지는 현재 서버 측에서 렌더링되고 NextJS의 정적 페이지 최적화는 없다.

NextJS에서 정적 페이지 최적화를 잃지 않고 사용하지 않을 수 있는 방법이 있는가?redux-persist그리고 어떤 페이지가 새로 고쳐졌을 때 여전히 클라이언트측 스토어에 수분을 공급할 수 있는가?

현재 코드 구조(간편성을 위해 일부 코드가 생략됨):

file: _app.tsx
import { wrapper } from 'store';

const MyApp = ({ Component, pageProps }: AppProps) => {
  return (
    <>
      <Navbar />
      <Component {...pageProps} />
    </>
  );
};


MyApp.getInitialProps = async (appContext) => {
  const appProps = await App.getInitialProps(appContext);

  return { ...appProps };
};

export default wrapper.withRedux(MyApp);
file: store.ts
import {
  combineReducers,
  configureStore,
  EnhancedStore,
  getDefaultMiddleware
} from '@reduxjs/toolkit';
import { createWrapper, MakeStore } from 'next-redux-wrapper';
import userReducer from 'lib/slices/userSlice';

const rootReducer = combineReducers({
  user: userReducer
});

const setupStore = (context): EnhancedStore => {
  const middleware = [...getDefaultMiddleware(), thunkMiddleware];

  if (process.env.NODE_ENV === 'development') {
    middleware.push(logger);
  }

  return configureStore({
    reducer: rootReducer,
    middleware,
    // preloadedState,
    devTools: process.env.NODE_ENV === 'development'
  });
};

const makeStore: MakeStore = (context) => setupStore(context);
export const wrapper = createWrapper(makeStore, {
  debug: process.env.NODE_ENV === 'development'
});
file: userSlice.ts
import { createSlice } from '@reduxjs/toolkit';
import { HYDRATE } from 'next-redux-wrapper';

const initialState = {
  isLoggedIn: false
}

export const userSlice = createSlice({
  name: 'user',
  initialState,
  reducers: {
    login: (state) => {
      state.isLoggedIn = true;
      localStorage.setItem('loggedInData', { isLoggedIn: true });
    }
  },
  extraReducers: (builder) => {
    builder
      .addCase(HYDRATE, (state, action: any) => {
        if (typeof window !== 'undefined') {
          const storedLoggedInData = localStorage.getItem('loggedInData');
          if (storedLoggedInData != null && storedLoggedInData) {
            const parsedJson = JSON.parse(storedLoggedInData);
            state.isLoggedIn = parsedJson.isLoggedIn ?? false;
          } else {
            state.isLoggedIn = false
          }
        }
      });
  }
});

export const isLoggedInSelector = (state: RootState) => state.user.isLoggedIn;

export default userSlice.reducer;
file: Navbar.tsx
import { useSelector } from 'react-redux';
import { isLoggedInSelector } from 'lib/slices/userSlice';

export default function Navbar() {
   const isLoggedIn = useSelector(isLoggedInSelector);
   return (
    <div className={`${ isLoggedIn ? 'logged-in-style' : 'logged-out-style'}`}>...</div>
   )
}

오늘도 같은 이슈였다.문제는 페이지 렌더링에서 클라이언트 스토리지를 분리하여 로 이동시켜야 한다는 것이다.useEffect구성 요소가 장착되는 위치.기본 아이디어는 먼저 페이지를 완전히 렌더링한 다음 클라이언트 저장소 정보를 사용하여 페이지를 업데이트하십시오.

고객의 로컬 스토리지를 직접 통합하면 수화작용을 방해할 수 있다.

여기 내가 사용하는 코드 샘플이 있다.

export default const MenuBar = () => {
  const isLoggedIn = useSelector((state) => state.isLoggedIn);
  useEffect(() => {
    // loads from clients local storage
    const auth = loadAuthenticationToken(); 
    if (auth !== null) {
      // updates the store with local storage data
      dispatch(actions.jwtTokenUpdate(auth)); 
    }
  }, [dispatch]);
  
  if (isLoggedIn) {
    return <p>you are logged in</p>;
  } else {
    return <p>please log in</p>;
  }
}

참고로 NextJS에 대한 github 이슈: https://github.com/vercel/next.js/discussions/17443

렌더링을 위해 창 액세스가 필요한 블로그 게시물: https://dev.to/adrien/creating-a-custom-react-hook-to-get-the-window-s-dimensions-in-next-js-135k

_app.js에서 getInitialProps를 사용하면 정적 최적화가 손실된다는 것이 문서에 언급되어 있다.서버 쪽에서는 왜 Redex를 사용하는지 모르겠는데, 개인적으로 클라이언트 쪽에서만 사용하라고 조언할 것이고, 후드 아래에서는 getInitialProps를 사용하기 때문에 더 이상 next-remex-wrapper를 사용하지 않아도 될 것이다.

Redex-toolkit의 예

또한 next-remensx-wrapper는 app.js/ts에서 getInitialProps를 스토어로 포장할 때 사용한다.그래서 당신이 이 라이브러리를 사용하고 그것으로 당신의 앱을 포장하면 당신은 자동적으로 정적 최적화를 잃게 된다.

참조URL: https://stackoverflow.com/questions/64805494/how-to-properly-hydrate-redux-state-in-nextjs-on-page-refresh

반응형