Prompt

Reactの関数型言語としての特徴が現れている例は?

お、これは**「Reactがなぜ関数型言語(Functional Programming, FP)の思想を取り入れているのか」**という、Reactの核心に迫る非常に良い質問だね!

ReactはJavaScriptというマルチパラダイムな言語の上に構築されているけど、特にバージョン16.8以降、Hooksの導入により、その関数型プログラミング(FP)の思想が色濃く現れるようになったよ。

最も特徴的なFPの思想が現れている例を3つ挙げて、詳しく解説するね!


1. 関数コンポーネント (Pure Functions)

Reactのコンポーネントがクラスベースから関数ベースに移行したことが、FP思想の最大の現れだよ。

🔹 関数型の特徴:純粋関数 (Pure Function)

関数コンポーネントは、原則として**純粋関数(Pure Function)**として振る舞うように設計されている。

特徴関数コンポーネントでの現れ影響
I. 入力が同じなら出力も同じProps(引数)が同じなら、描画結果(出力)も常に同じになる。予測可能でテストしやすいコードになる。
II. 副作用がない (No Side Effects)コンポーネント本体の実行は、外部の状態(ネットワーク、DOM、時間)を変更しない。複数のコンポーネントを同時に実行しても安全になる(並行処理)。

💻 実現例: Greeting コンポーネント

JavaScript

// 外部の状態 (global.time) に依存しない
// 自身の Props (name) のみに依存する
const Greeting = (props) => { 
  // 副作用なし: ネットワーク通信やDOM操作をここで直接行わない
  return <h1>Hello, {props.name}</h1>;
};

これにより、Reactはコンポーネントを何度でも安全に実行したり、結果をキャッシュしたり(React.memo)することが可能になっているんだ。


2. Hooksによる状態管理と副作用の分離

関数型言語では、状態変更や外部とのやり取り(副作用)を「関数」から切り離し、明確に制御された場所で行うことが重視されるよ。

🔹 関数型の特徴:副作用の分離

Hooks(特に useStateuseEffect)は、「状態」と「副作用」という、純粋関数から排除したい要素を、コンポーネント(純粋関数)本体から分離するための仕組みだよ。

Hooks担当するFP的要素役割
useStateイミュータブルな状態状態を直接変更せず、新しい状態を返す関数(セッター)を経由して、常に新しい値として扱う。
useEffect副作用の隔離ネットワーク通信、DOM操作、タイマーなど、純粋性を損なう操作を、このフック内に隔離する。

💻 実現例: useEffect による副作用の分離

JavaScript

const DataFetcher = ({ url }) => {
  const [data, setData] = useState(null); // 状態の管理

  // 💡 副作用(データ取得)をコンポーネント本体から分離・隔離する
  useEffect(() => {
    // 外部の世界(ネットワーク)と通信する
    fetch(url).then(res => res.json()).then(setData);
    
    // クリーンアップ関数を返すことで、副作用を片付けるロジックも隔離する
    return () => { 
      // 例: WebSocketを切断する処理など
    };
  }, [url]); // 依存配列: urlが変わったときだけ副作用を実行する

  return data ? <p>{data.message}</p> : <p>Loading...</p>;
};

コンポーネント本体(return文より上)は純粋さを保ちつつ、必要な外部とのやり取りは useEffect というFPの「モナド」に似た制御構造の中だけで行う、という思想なんだ。


3. データのイミュータビリティ(不変性)

関数型プログラミングでは、データの**不変性(Immutability)**が極めて重要だよ。

🔹 関数型の特徴:不変性

Reactは、状態(State)やプロパティ(Props)を直接変更することを推奨していない。常に新しいオブジェクトや配列を作成することで、データの変更を表現する。

💻 実現例: 配列の更新

【悪い例(命令型、ミュータブル)】

JavaScript

// 🙅‍♀️ 配列を直接変更しているため、Reactが差分を検知しにくい
list.push(newItem); 
setList(list); 

【良い例(関数型、イミュータブル)】

JavaScript

// 🙆‍♀️ スプレッド構文で常に新しい配列を生成し、不変性を保つ
setList(prevList => [...prevList, newItem]); 

この不変性の原則を守ることで、Reactのレンダリングエンジンは「PropsとStateが変わったかどうか」を**古いオブジェクトと新しいオブジェクトの参照比較(shallow equality check)**だけで簡単に、かつ高速に判断できる。これにより、無駄な再レンダリングを防ぎ、パフォーマンスを最適化しているんだ。


まとめ

Reactの関数コンポーネントとHooksは、以下のFPのコアな思想をWebフロントエンドに持ち込んだと言えるよ。

  1. コンポーネントを純粋関数として扱う

  2. 副作用と状態の変更を制御された場所に隔離する

  3. 状態の更新を常に不変なデータ(新しいオブジェクト)で行う

これらの特徴が、Reactを予測可能テストしやすく、そして並行処理に強いライブラリにしているんだ。👍

この話を踏まえて、関数型プログラミングのもう一つの重要な概念である**「高階関数(Higher-Order Functions)」**がReactのコードでどのように現れているか(例: HOCやカスタムHooksなど)について話してみるのも面白そうだけど、どうかな?