0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Context API備忘録

Posted at

はじめに

年末年始にReactとTypeScriptの旅に出てきました。
行ったことの備忘録として記載します。
理解が浅い部分もあるため、諸々ご容赦いただけると助かります。

Context APIとは

Context APIとはなにか、ないとどうなるかを記載します。

Context APIのない世界

複数間コンポーネントで値の受け渡しをする際、どうしても煩雑になりがちです。
極端な例ですが、App.tsxから子コンポーネント、更に孫へと受け渡すにつれてコードがバケツリレーと化します。
React.png

Context APIのある世界

グローバル(語弊あり)な空間から値を取得、更新することができます。
バケツリレーの必要はなくなりますが、コンポーネントが特定の値に依存してしまうため、再利用性は下がります。

Context APIの使い方

使い方は以下の通りです。

  1. Contextオブジェクト生成
  2. Providerの設置
  3. Contextの利用

Contextオブジェクト生成

AppContext.tsx
interface AppContextType {
  users: User[];
  setUsers: React.Dispatch<React.SetStateAction<User[]>>;
}

export const AppContext = createContext<AppContextType | undefined>(undefined);

export const AppContextProvider = ({ children }: { children: ReactNode }) => {
  const [users, setUsers] = useState<User[]>([]);

  return (
    <AppContext.Provider value={{ users, setUsers }}>
      {children}
    </AppContext.Provider>
  )
};

AppContextcreateContextで生成したContextオブジェクトです。
AppContextProviderはProviderの設置で使用します。

Providerの設置

App.tsx
function App() {
  return (
    <AppContextProvider>
      <CssBaseline />
      <Router>
        <Routes>
          <Route path="/" element={<AppLayout />}>
            <Route index element={<Home />} />
            <Route path="/report" element={<Report />} />
            <Route path="/*" element={<NoMatch />} />
          </Route>
        </Routes>
        </Router>
      </AppContextProvider>
  );
}

先ほど作成したAppContextProviderをContextを作成したいコンポーネントの上位ツリーに設置します。
つまり、今回の場合には、Home.tsxReport.tsxAppContextを読み取れますが、App.tsxの中では読み取れません。
あくまでAppContextProvider配下のコンポーネントでだけ読み取れます。

Contextの利用

AppContext.tsx
// useAppContextのカスタムフック
export const useAppContext = () => {
  const context = useContext(AppContext);
  if (!context) {
    // AppContextProvider配下のコンポーネントではない場所での呼び出し
    throw new Error("useAppContext must be used within a AppContextProvider");
  }
  return context;
}

useContext(AppContext)で呼び出した際にundefinedか判定しなければいけません。
毎度実施するのは面倒ですので、カスタムフックとして記載することで呼び出し側でのコードが簡潔になります。

Home.tsx
export default Home = () => {
  const { users } = useAppContext();
  return (
  ...
  ...
  )
}

Home.tsxではuseAppContext()を使用するだけでusersが取り出せました。

動的な値の取得について

usersを元にuser.registration_atでfilterしたselectedMonthRegistrationUsersを各所で使用したいとします。
その場合、AppContext.tsxではなく、別ファイルにカスタムフックとしてまとめるほうが複雑になりにくくおすすめです。

useSelectedMonthRegistrationUsers.tsx
export default const useSelectedMonthRegistrationUsers = (): User[] => {
  const { users, registration_from, registration_to } = useAppContext();

  const selectedMonthRegistrationUsers = useMemo(() => {
    return users.filter((user) => {
      const registrationDate = new Date(user.registration_at);
      const fromDate = new Date(registration_from);
      const toDate = new Date(registration_to);

      return registrationDate >= fromDate && registrationDate <= toDate;
    });
  }, [users, registration_from, registration_to]);

  return selectedMonthRegistrationUsers;
}

なお、カスタムフックはuse~から始めるのが決まりとのことです。
また、useMemoを使用することで、第二引数に渡した値([users, registration_from, registration_to])が変更された時だけ更新されるようになります。

さいごに

用法用量を守って使わないと、いけない。
銀の弾丸はない。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?