Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Persist Storage 가 서버사이드에 존재하지 않아 hydration mismatch 발생하는 버그 해결 #18

Open
toothlessdev opened this issue Apr 8, 2024 · 1 comment

Comments

@toothlessdev
Copy link
Member

toothlessdev commented Apr 8, 2024

resolve #17

✨ 구현한 기능

서버 사이드에서 Redux Persist 의 WebStorage API 의 부재로 사전렌더링시 오류 발생

  1. 서버 사이드 Storage 임시로 구현 및 서버사이드와 클라이언트 사이드에서 리턴되는 storage 분기
// /src/store/persist/persistStorage.ts
import createWebStorage from "redux-persist/lib/storage/createWebStorage";

const serverSideStorage = () => {
    return {
        // eslint-disable-next-line @typescript-eslint/no-unused-vars
        getItem: (_key: string): Promise<string> => {
            return new Promise((resolve) => {
                resolve("{}");
            });
        },
        // eslint-disable-next-line @typescript-eslint/no-unused-vars
        setItem: (_key: string, _item: string): Promise<void> => {
            return new Promise((resolve) => {
                resolve();
            });
        },
    };
};

export const persistStorage = typeof window !== "undefined" ? createWebStorage("local") : serverSideStorage();
  1. PersistGate 에서 typeof window === "undefined", 서버에서 실행시 loading props 가 아닌 children props 를 렌더링하도록 수정
// /src/store/persist/PersistGate.ts
if (typeof window === "undefined") return this.props.children;
return this.state.bootstrapped ? this.props.children : this.props.loading;
  1. persistStore 가 자동으로 persist/PERSIST persist/REHYDRATE 액션을 디스패치 하지 않도록 manualPersist 설정
// /src/store/store.ts
export const persistor = persistStore(store, { manualPersist: true } as PersistorOptions);
  1. entry-client.ts 에서 hydration 이후 client 측에서 persist 액션 디스패치 하도록 설정
const root = ReactDOM.hydrateRoot(
    document.getElementById("app") as HTMLElement,
    <BrowserRouter>
        <App isClient={false} />
    </BrowserRouter>,
);

root.render(
    <BrowserRouter>
        <App isClient={true} />
    </BrowserRouter>,
);
export default function App({ isClient }: { isClient: boolean }) {
    useEffect(() => {
        if (isClient) persistor.persist();
    }, [isClient]);

📢 논의하고 싶은 내용

🎸 기타

  • 사전렌더링은 성공하였으나 사전렌더링된 HTML 이 hydration 되기전에 Client Side 에서 재렌더링이 진행되어 Client Side Rendering 으로 전환되는 현상 발생
image
@toothlessdev toothlessdev pinned this issue Apr 8, 2024
@toothlessdev
Copy link
Member Author

toothlessdev commented Apr 8, 2024

image

React Profiler 확인결과 hydrateRoot 호출로, 사전렌더링된 페이지에 하이드레이션이 발생하고,

image

PersistGate 에 의해 재렌더링이 발생하는데, 이는

image

State Changed : bootstrapped
즉, persistor.persist() 가 호출되어 클라이언트 사이드에서 WebStorage 로 부터 상태를 복구되고
복구가 완료되었다는 상태 (bootstrapped) 가 변경되며 발생하는 렌더링으로
정상적인 렌더링으로 보임

@toothlessdev toothlessdev changed the title Hotfix: Persist Storage 가 서버사이드에 존재하지 않아 hydration mismatch 발생하는 버그 해결 Persist Storage 가 서버사이드에 존재하지 않아 hydration mismatch 발생하는 버그 해결 Apr 17, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant