未経験からエンジニア 奮闘記

未経験からエンジニアに自由に生きる途中

MENU

Next.js での useContext の基本的な使い方

Next.js での useContext の基本的な使い方

今回は、Next.js を使って useContext をどうやって活用するのか、そしてどんなときに使うべきなのかをまとめてみました!また、ディレクトリ構成にも触れていきます。

どんな時に使うか?

useContext は、コンポーネントツリーの深い階層にあるコンポーネントが、状態や関数を簡単に利用できるようにするためのものです。通常、プロップドリリング(props drilling: バケツリレーとも言う)を避けたいときに使います。

例えば、以下のコードを見てください。プロップドリリングが発生している例です。

ディレクトリ構成:

my-next-app/
├── pages/
│   ├── index.js
├── components/
│   ├── Header.js
│   ├── Main.js
│   ├── Profile.js

コード:

// pages/index.js
import React, { useState } from 'react';
import Header from '../components/Header';
import Main from '../components/Main';

const Home = () => {
  const [user, setUser] = useState({ name: 'たけし' });

  return (
    <div>
      <Header user={user} />
      <Main user={user} />
    </div>
  );
};

export default Home;
// components/Header.js
const Header = ({ user }) => {
  return <h1>Welcome, {user.name}!</h1>;
};

export default Header;
// components/Main.js
import Profile from './Profile';

const Main = ({ user }) => {
  return (
    <div>
      <Profile user={user} />
    </div>
  );
};

export default Main;
// components/Profile.js
const Profile = ({ user }) => {
  return <p>User's name is {user.name}</p>;
};

export default Profile;

このコードでは、user プロップをツリーの深いところまで渡さなければなりません。これがプロップドリリングです。

最近では、Typescriptも導入されていることが多いので、 Propsの型定義も全てのファイルに記載しなくてはいけなかったり、冗長なコードが増えてしまいます。

useContext を利用したコードとメリットを解説

では、これを useContext を使って解決してみましょう。Next.js では、コンテキスト関連のファイルを contexts ディレクトリに格納するのがおすすめです。今回は、ユーザー情報を更新するために、setUser もコンテキストで渡します。

ディレクトリ構成:

my-next-app/
├── pages/
│   ├── index.js
├── components/
│   ├── Header.js
│   ├── Main.js
│   ├── Profile.js
│   ├── UpdateUser.js
├── contexts/
│   ├── UserContext.js

コード:

// contexts/UserContext.js
import { createContext } from 'react';

const UserContext = createContext();

export default UserContext;
// pages/index.js
import React, { useState } from 'react';
import Header from '../components/Header';
import Main from '../components/Main';
import UserContext from '../contexts/UserContext';

const Home = () => {
  const [user, setUser] = useState({ name: 'たけし' });

  return (
    <UserContext.Provider value={{ user, setUser }}>
      <div>
        <Header />
        <Main />
      </div>
    </UserContext.Provider>
  );
};

export default Home;
// components/Header.js
import React, { useContext } from 'react';
import UserContext from '../contexts/UserContext';

const Header = () => {
  const { user } = useContext(UserContext);
  return <h1>Welcome, {user.name}!</h1>;
};

export default Header;
// components/Main.js
import Profile from './Profile';
import UpdateUser from './UpdateUser';

const Main = () => {
  return (
    <div>
      <Profile />
      <UpdateUser />
    </div>
  );
};

export default Main;
// components/Profile.js
import React, { useContext } from 'react';
import UserContext from '../contexts/UserContext';

const Profile = () => {
  const { user } = useContext(UserContext);
  return <p>User's name is {user.name}</p>;
};

export default Profile;
// components/UpdateUser.js
import React, { useContext } from 'react';
import UserContext from '../contexts/UserContext';

const UpdateUser = () => {
  const { setUser } = useContext(UserContext);

  const handleChangeName = () => {
    setUser({ name: 'ひろし' });
  };

  return <button onClick={handleChangeName}>名前をひろしに変更</button>;
};

export default UpdateUser;

メリット

  • コードのシンプル化:プロップを何度も渡す必要がなくなります。
  • メンテナンス性の向上:一度設定すれば、どこからでも簡単にコンテキストにアクセスできるので、変更が楽になります。
    • Providerの valueにsetState関数を渡せば良い
  • 読みやすさ:プロップドリリングがないので、コードがより読みやすくなります。

まとめ

useContext は、React や Next.js で状態管理や関数をコンポーネントツリーの深い階層で簡単に共有したいときに非常に便利です。プロップドリリングを避け、コードをよりシンプルかつメンテナンスしやすくしてくれます。Next.js の場合は、contexts ディレクトリを使ってコンテキストを整理すると良いでしょう。次回のプロジェクトではぜひ試してみてくださいね!

これで、useContext の基本的な使い方とそのメリットについての説明は終わりです。お読みいただきありがとうございます!