Recoilによる、開発体験は非常によかったが、下記のエラーに悩まされた。
app_1 | Duplicate atom key "isLoading". This is a FATAL ERROR in app_1 | production. But it is safe to ignore this warning if it occurred because of app_1 | hot module replacement.
Issueはこちら
やりたいこととしては、シンプルなので、React Context APIを使用する。
などの状態をグローバルステート(React Context API)で管理し、開発体験を向上させる。
コンテクストは各階層で手動でプロパティを下に渡すことなく、コンポーネントツリー内でデータを渡す方法を提供します。
context/state.jsimport { useState, createContext, useContext } from 'react'; import Loading from '@/components/atoms/loading'; // 👈 使用するローディングコンポーネント // 👇 Contextの作成 const AppContext = createContext({ loading: false, setLoading: (_) => {}, }); // 👇 _app.tsxでコンポーネントツリーの上の方に追加する export const AppWrapper = ({ children }) => { const [loading, setLoading] = useState(false); const value = { loading, setLoading, }; return ( <AppContext.Provider value={value}> <Loading loading={loading} /> {children} </AppContext.Provider> ); }; // 👇 Pageコンポーネントなどで読み込む export const useAppContext = () => useContext(AppContext);
pages/_app.tsximport React from 'react'; import { AppProps } from 'next/app'; import { AppWrapper } from '@/context/state'; function MyApp({ Component, pageProps }: AppProps) { return ( <> {/* 👇 Context を コンポーネントツリーに追加 */} <AppWrapper> <Component {...pageProps} /> </AppWrapper> </> ); } export default MyApp;
pages/index.tsximport { useAppContext } from '@/context/state'; export default function Index() { const { setLoading } = useAppContext(); const func = () => { setLoading(true); // 👈 ローディングの表示 setLoading(false); // 👈 ローディングの非表示 } }
import { useAppContext } from '@/context/state'; const { setLoading } = useAppContext(); const { data: user, error } = useSWR('/api/user'); if (!user) { setLoading(true) return <></>; } setLoading(false)
上記の実装だと、下記のエラーが発生する。
react-dom.development.js:67 Warning: Cannot update a component (`AppWrapper`) while rendering a different component (`Index`). To locate the bad setState() call inside `Index`,
レンダリングできていない状態で、Index以外のHooksを呼び出すと警告される。(実行はできるが)
💡 回避手段: staticなローディングコンポーネントを返す。(もっといい方法があるかもしれない)
import StaticLoading from '@/components/atoms/static-loading'; const { data: user, error } = useSWR('/api/user'); if (!user) return <StaticLoading />;