見出し画像

React: Compound Componentsパターンを用いたリファクタリング

こんにちは、株式会社POLのエンジニア・ミズノです。テックブログ推進と言いながら前回の投稿から随分時間が経ってしまいました。気合い入れ直して頑張ります。

今回は社内イベントで行われた、Reactコードのリファクタリングを紹介します。POLでは毎週のエンジニア勉強会(30分のLT会)を行なっていますが、それとは別にエンジニアラジオと称してトークイベントを始めました。しばらくはクローズドなイベントですが、近いうちに公開する可能性もあります。

お題はリファクタリング

POLのフロントエンドはReactを採用しています。そこで実際によく書きがちなコードを取り上げて、その場でリファクタリングしてみました。聞き専メンバーだけでなくコメント、質問もあり、モブプロのような感じで進めました。

お題コード

お題は以下のコードです。コードは要点のみ取り出した物です。実際はもっと複雑なコードをリファクタしているのでご注意ください。

簡単に説明します。見ての通りpropsでフラグが渡ってきます。このフラグがTrueの場合にNewという文字が表示されます。JSX部分にフラグ変数を用いて、分岐処理が入っています。

import React from "react";

type Props = {
  isNew: boolean;
};


export const ProfileComponent: React.FC<Props> = ({isNew}) => {
 return (
   <div>
     <h2>プロフィール</h2>
     {
       isNew && (
         <div>
           <p>NEW</p>
         </div>
       )
     }
   </div>
 );
}

分岐処理部分を抜き出しました。

{
    isNew && (
     <div>
       <p>NEW</p>
     </div>
    )
}

JSX部分に分岐コードが入ると読みづらいですよね。JSX部分はシンプルで読みやスクしたい。そしてもっと宣言的に書きたい!

それでは早速リファクタしてみましょう。

JSXからフラグを外す

まずはNew表示の判定を切り出します。これでProfileComponentはシンプルになりました…と思いきやNewコンポーネントに移っただけですね。

export const ProfileComponent: React.FC<Props> = ({ isNew }) => {
 return (
   <div>
     <h2>プロフィール</h2>
     <New isNew={isNew} />
   </div>
 );
};

// Newを出力する部分を切り出す。
const New: React.FC<any> = ({ isNew }) => {
 return isNew ? (
   <div>
     <p>NEW</p>
   </div>
 ) : null;
};

Compoundパターンの利用

そこで今回はCompoundパターンを利用してみたいと思います。Compoundパターンは以下のブログで詳細が解説されています。

https://kentcdodds.com/blog/compound-components-with-react-hooks/

Newの表示判定部分を別に切り出し、実際に表示されるものはProfileComponentに残っています。見通しも良くなり、宣言的にJSX部分が記述できるているのではないでしょうか?

export const ProfileComponent: React.FC<Props> = ({ isNew }) => {
 return (
   <div>
     <h2>プロフィール</h2>
     <New isNew={isNew}>
       <div>
         <p>NEW</p>
       </div>
     </New>
   </div>
 );
};

const New: React.FC<any> = ({ isNew, children }) => {
 return isNew ? children : null;
};

Contextを利用してPropsを減らす

props経由でisNewフラグ渡していましたが、contextを利用することでJSX部分がよりシンプルになりました。contextはとても便利なので多用します。

// context
type contextType = {
 isNew: boolean;
};

const context = React.createContext<contextType>(
    Object.create(null) as contextType
);

export const ProfileComponent: React.FC<Props> = ({ isNew }) => {
 const value = { isNew };
 return (
   <context.Provider value={value}>
     <div>
       <h2>プロフィール</h2>
       <New>
         <div>
           <p>NEW</p>
         </div>
       </New>
     </div>
   </context.Provider>
 );
};

// Compound components
const New: React.FC<any> = ({ children }) => {
 const { isNew } = useContext(context);
 return isNew ? children : null;
};

今回のコードはシンプルすぎたので、最終コードの方がコード量が増えましたが、読みやすくなったのではないでしょうか。

まとめ

Reactの実装方法はエンジニアごとで差があるため、POL内でも知見を共有しあい、改善を進めています。こういった学びを得やすいは環境は、POLの特徴だと思います。そんなPOLではエンジニアを絶賛募集中です。カジュアル面談はいつでもウェルカムですので、気軽にご応募ください。

コメントや下記のリンクからご応募いただけると嬉しいです。

ちなみにPDMも募集しています!


Pattern Vectors by Vecteezy

この記事が気に入ったらサポートをしてみませんか?