網站搜尋

reactjs - 在 next.js 中,逐步將 pages 升級到 app 路由時,如何使用 context provider 共享狀態?


我正在嘗試在 Next.js 專案中從 pages 漸進式升級到 app 路由器。

我在我的 _app 中有一個 <SessionProvider>,它結合 useState 使用 localStorage 來存儲我的會話令牌。

像這樣的東西:

const useLocalStorage = <T>(key: string, defaultValue: T) => {
  const [value, setValue] = useState(() => {
    let currentValue;

    try {
      currentValue = JSON.parse(
        localStorage.getItem(key) || String(defaultValue)
      );
    } catch (error) {
      currentValue = defaultValue;
    }

    return currentValue;
  });

  useEffect(() => {
    localStorage.setItem(key, JSON.stringify(value));
  }, [value, key]);

  return [value, setValue];
};

…

const [sessionToken, setSessionToken] = useLocalStorage<string | null>("session_token", null);

我認為我遇到的問題是,這個 SessionProvider 同時被渲染在舊的 /pages/_app.page.tsx 和新的 /app/layout.tsx 中——它們是不同的實例——擁有不同的狀態。所以即使 localStorage 是共享的,內部狀態也不是。

如果我現在在應用程式路由下有一個受保護的頁面,該頁面會重定向到舊頁面路由下的登入頁面,如果我這樣調試,看起來會發生以下情況:

應用路由器的上下文提供者在初始化時沒有值。由於用戶未登入,因此會重定向到 /pages 下的登入頁面,在那裡用戶登入,但這是在組件樹中另一個上下文提供者實例下。然後重定向回第一個受保護的頁面時,本地存儲不會從第一個上下文提供者重新讀取,狀態也沒有因登入而更新。

所以 useLocalStorage 的使用方式並不會對本地儲存進行響應,因此僅能作為具有對本地儲存寫入響應性的單例使用。

所以:

  • 在 Next 裡有哪裡可以放一個包裹元件的佈局,這個佈局可以在 app router 和 pages router 之間共享嗎?這樣我就可以在兩者之間使用相同的 ContextProvider。
  • 或者有沒有一種更簡單的方法來做到這一點,而不需要涉及信號或單例狀態?
  • 或者如果我無法共享組件層級結構,我通常在 React 中如何做到這一點?

我看到我可能可以使用 https://usehooks.com/uselocalstorage,看起來它可以從 localstorage 進行響應式更新:https://github.com/uidotdev/usehooks/blob/dfa6623fcc2dcad3b466def4e0495b3f38af962b/index.js#L616

但我寧可要一些簡單的東西…