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?

Reactのコンポジションの活用

Posted at

Reactにおけるコンポジション

React では、props に ReactNode 型の値を渡すことで、コンポーネントを他のコンポーネントに埋め込むコンポジションが可能です。

function Parent(props) {
  return <div>{props.children}</div>;
}

function Root(props) {
  return (
    <Parent>
      <Button>Click</Button>
    </Parent>
  );
}

children 以外の props を利用するパターン

children 以外の props を使うことで、特定の要素を柔軟にカスタマイズできます。

function Parent(props) {
  return (
    <div>
      {props.header}
      {props.children}
    </div>
  );
}

function Root(props) {
  return (
    <Parent header={<div>Header</div>}>
      <Button>Click</Button>
    </Parent>
  );
}

よく使われているパターン

Provider

Provider パターンでは、 children をそのまま受け取り、ラップする形で値を提供します。子要素の内容には関与しません。

import { createContext } from "react";

const Context = createContext("");

function Root(props) {
  const value = getValue();
  return (
    <Context.Provider value={value}>
      {props.children}
    </Context.Provider>
  );
}

children を使わないパターンとその問題点

children を使わずに Provider 内で直接子コンポーネントを描画するパターンも考えられますが、パフォーマンス面で問題があります。

import { createContext } from "react";

const Context = createContext("");

// childrenを渡す必要
function Root(props) {
  const value = getValue();
  return (
    <Context.Provider value={value}>
      <Child />
    </Context.Provider>
  );
}

この場合、 Root が再レンダリングされるたびに Child も再レンダリングされてしまいます。children を Provider に渡すことで、不要な再レンダリングを防ぐことができます。

コンポジションを使うことによるメリット

コンポーネントの再レンダリングの影響を受けにくい

通常、Reactでは親コンポーネントが再レンダリングされると、子コンポーネントも再レンダリングされます。しかし、コンポジションを利用して children として子コンポーネントを渡した場合、その子コンポーネントは親の再レンダリングの影響を受けません。

先ほどの Provider の例では、children として渡さないと Provider を含むコンポーネントが再レンダリングされるたびに Child も再レンダリングされてしまいます。children を適切に利用することで、この問題を回避できます。

React Server Components の活用

コンポジションは React Server Components (RSC) と相性が良いです。RSC では、親コンポーネントが Server Component か Client Component かによって、子コンポーネントの動作も変わります。1

しかし、コンポジションを利用すれば、Client Component 内に Server Component を組み込むことが可能です。
例えば、Next.js では Layout に Provider を配置することがあります。この場合、children を通じて Server Component をラップできます。

"use client"

function Provider(props) {
  return (
    <SomeProvider>
      {props.children}
    </SomeProvider>
  );
}

// -----------------------

function Layout(props) {
  return (
    <Provider>
      <ServerComponent />
    </Provider>
  );
}

この方法を使うことで、ページ全体を Client Component にすることなく、Provider の部分のみを Client Component にできます。

まとめ

コンポジションを活用することで、コンポーネントの子要素の詳細に依存せずに設計できるため、再レンダリングの影響を抑えやすくなります。

また、React Server Components (RSC) との組み合わせにより、Client Component の範囲を最小限に抑えつつ、柔軟なコンポーネント構成を実現できます。

適切なコンポジションの設計により、可読性・保守性・パフォーマンスの向上が期待できるため、積極的に取り入れていきましょう。

  1. "use client" などのディレクティブを付与している場合は例外です。

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?