🍣

React Componentはあくまでjs(ts) objectだと認識する

2024/01/22に公開

概要

タイトルに書いてあることは当たり前のことなのですが、改めてこれを認識するとリファクタリングに繋がるなぁと感じております。具体的には以下のようなことが当然可能であるということです。

// 以下、イメージです。
const componentsMap = {
  key1: SomeComponent1,
  key2: SomeComponent2
}

// ここで変数で受け取ったcomponentを
const SomeComponent = componentsMap["key1"]

// こんなふうに呼び出せます。
return(<SomeComponent props="props">)

まぁ、当たり前ですよね。リファクタ例を以下に示しますので、ご興味のある方はご覧いただければと思います。

説明

引数によって画像を切り替えるcomponentとして以下のように最初作ってましたが、もう少しsmartな方法はないものかと考えておりました。

// SVG 画像をcomponentとしてimport
import Img1 from '../images/img1.svg';
import Img2 from '../images/img2.svg';]

type ImgProps = {
  imgType: 'img1' | 'img2'; //画像増やすたびにここも増やすのか。。。
  width: number;
  height: number;
};

const Img = (props: ImgProps) => {
  return (
      {/* ここがイマイチ。画像増えてくるとかなり冗長ですよねー */}
      {props.imgType === 'img1' ? (
        <Img1 width={props.width} height={props.height} />
      ) : props.imgType === 'img2' ? (
        <Img2 width={props.width} height={props.height} />
      ) : (
        <></>
      )}
  );
};

以下のようにリファクタできました、という話です。

// SVG 画像をcomponentとしてimport
import Img1 from '../images/img1.svg';
import Img2 from '../images/img2.svg';]

// key-valueでcomponentを持つ。画像増えたらここに追加するだけでよい。
const ImgSourceMap = {
  img1: Img1,
  img2: Img2,
} as const;

// type ImgType = "img1" | "img2" となります。
// 型プログラミングによって、こちらの型も自然に拡張されるのでよし。
type ImgType = keyof typeof ImgSourceMap;

type ImgProps = {
  imgType: ImgType;
  width: number;
  height: number;
};

const Img = (props: ImgProps) => {
  // 変数としてcomponentを受け取る
  const ImgComponent = ImgSourceMap[props.imgType];
  
  return (
            {/* componentとして使える。画像増えてもここは編集不要。 */}
      <ImgComponent width={props.width} height={props.height} />
  );
};

何かのご参考になれば幸いです。

Discussion