microCMS

Reactのベストプラクティスとコード削減パターン - パート2

松田 承一

この記事は公開後、1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

本記事は React best practices and patterns to reduce code - Part2 を提供元の事前許可を得たうえで翻訳したものです。

元の記事に従いタイトルに「ベストプラクティス」と含んでいますが、実際にはベストプラクティスは規模や状況によって大きく異なります。
チームの状況にあわせて参考にしていただければと思います。

=====

これは全3パート中の第2パートとなる記事です。


時間を無駄にしないために早速Reactのベストプラクティスとコード削減についてみていきましょう。まずは最も一般的な内容から始めます。

コンポーネントが子要素を持たない場合はself-closing tagする

よくないコード:

return <Component></Component>

よいコード:

return <Component />

jsx要素の中で関数を書かない

よくないコード:

return (
  <div>
    <button
      onClick={() => {
        setCount(1);
        // ...
      }}
    >
      Click
    </button>
  </div>
);

よいコード:

const onClick = useCallback(() => {
  setCount(1);
  // ...
}, [deps]);

return (
  <div>
    <button onClick={onClick}>Click</button>
  </div>
);


同時に複数のstateを更新する場合はstateをオブジェクトにする

連続でsetState(setNamesetCount)を呼び出すのはやめましょう。これは不要なレンダリングを引き起こしてしまう、とても良くあるミスです。1回のみのsetState呼び出しが好ましいです。

よくないコード:

const [count, setCount] = useState(0);
const [name, setName] = useState("");

const onClick = () => {
  setTimeout(() => {
    setName("John");
    setCount(count + 1);
  }, 1000);
};

よいコード:

const [state, setState] = useState({
  count: 0,
  name: "",
});

const onClick = () => {
  setTimeout(() => {
    setState((prevState) => ({
      ...prevState,
      name: "John",
      count: prevState.count + 1,
    }));
  }, 1000);
};

注釈:React 18で自動バッチ機能が追加され、不要なレンダリングはReact自身によって最適化されるようになりました

コンポーネントのスタイリングにはstyled-componentsを使う。これはJSXでCSSを記述することやアプリケーション独自のCSS設定を避けるためにも役立ちます。

ただし主観による意見ですのでその点ご注意ください。

よくないコード:

return <div style={{ backgroundColor: "red" }}></div>;

よいコード:

const Container = styled.div`
  background-color: ${({ theme }) => theme.colors.background};
  padding: 1rem;
`;

よりよいコード:

const getPrimaryColor = ({ theme }) => theme.colors.primary;
const getDefaultColor = ({ theme }) => theme.colors.secondary;

const Button = styled.button`
  background-color: ${getPrimaryColor};
  color: ${getDefaultColor};
`;

注釈:themeから色やスタイルを取り出す関数を作りコンポーネントに渡します。これはコード量を減らすことに役立ちます。

class-basedなコンポーネントを辞めてfunctionalなコンポーネントを作る

よくないコード:

class Counter extends Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0,
    };
    this.onClick = this.onClick.bind(this);
  }

  onClick = () => {
    this.setState({
      count: this.state.count + 1,
    });
  };

  render() {
    return <button onClick>Click me</button>;
  }
}

よいコード:

const Counter = () => {
  const [count, setCount] = useState(0);
  const onClick = () => setCount(count + 1);
  return <button>Click me</button>;
};

注釈:functionalなコンポーネントは開発時間やコード量を減らすだけでなくバンドルサイズを60%近く減らす効果もあります。

React.memoで不要なレンダリングを避ける

よくないコード:

return (
  <ui>
    {items.map((item) => (
      <Component>{item}</Component>
    ))}
  </ui>
);

よいコード:

const MemoComponent = React.memo(Component);
return (
  <ui>
    {items.map((item) => (
      <MemoComponent>{item}</MemoComponent>
    ))}
  </ui>
);

注釈:ただしpropsの変化によりコンポーネントを頻繁にレンダリングする箇所ではReact.memo()を使用しないように注意しましょう。

JSXのショートハンドを使う(booleanを渡す例)

よくないコード:

return <button disabled={true}>Submit</button>;

よいコード:

return <button disabled>Submit</button>;

if-elseの代わりに三項演算子を使う

よくないコード:

if (isLoading) {
  return <div>Loading...</div>;
} else {
  return <div>Data</div>;
}

よいコード:

return isLoading ? <div>Loading...</div> : <div>Data</div>;

switch文の代わりにオブジェクトを使う。(前回の記事と同様)

よくないコード:

switch (props.type) {
  case "ADMIN":
    return <Admin />;
  case "USER":
    return <User />;
  default:
    return <NotFound />;
}

よいコード:

const componentMap = {
  ADMIN: Admin,
  USER: User,
  NOT_FOUND: NotFound,
};

const Component = componentMap[props.type];
return <Component />;

よりよいコード:

const componentMap = {
  ADMIN: React.lazy(() => import("../components/Admin")),
  USER: React.lazy(() => import("../components/User")),
  NOT_FOUND: React.lazy(() => import("../components/NotFound")),
};

const Component = componentMap[props.type];
return <Component />;

複数の名前を指定したpropsよりもスプレッド構文を利用する

よくないコード:

const { name, age, role } = props;
return (
  <>
    <Component name={name} age={age} role={role} />
  </>
);

よいコード:

return (
  <>
    <Component {...props} />
  </>
);

文字列をコンポーネントに渡す場合は中括弧を削除する

よくないコード:

return <Component name={"John"} />;

よいコード:

return <Component name="John" />;

classNameやstyleといった値をReactのカスタムprops名にしない

よくないコード:

return (
  <Component style="bordered">
);

よいコード:

return (
  <Component variant="bordered">
);

divやspanなどの代わりにReactのfragmentを使用する

よくないコード:

return (
  <div>
    <span>{props.name}</span>
    <span>{props.age}</span>
  </div>
);

よいコード:

return (
  <>
    <span>{props.name}</span>
    <span>{props.age}</span>
  </>
);

if内で値を返却する場合はelseを書かない

よくないコード:

if (props.name) {
  return <div>{props.name}</div>;
} else {
  return <div>No name</div>;
}

よいコード:

if (props.name) {
  return <div>{props.name}</div>;
}
return <div>No name</div>;

keyプロパティを指定する際にもdivやspanの代わりにReact.Fragmentを利用する

よくないコード:

return (
  <container>
    {list.map((item) => (
      <div key={item.id}>
        <SomeComponent />
        <SomeAnotherComponent />
      </div>
    ))}
  </container>
);

よいコード:

return (
  <>
    {list.map((item) => (
      <React.Fragment key={item.id}>
        <SomeComponent />
        <SomeAnotherComponent />
      </React.Fragment>
    ))}
  </>
);


ここまでお読みいただきありがとうございます😊

--

今後もWebフロントエンドにまつわる最新情報を発信予定です。
興味のある方はぜひ 公式Twitter をフォローしてください。

まずは、無料で試してみましょう。

APIベースの日本製ヘッドレスCMS「microCMS」を使えば、 ものの数分でAPIの作成ができます。

microCMSを無料で始める

microCMSについてお問い合わせ

初期費用無料・14日間の無料トライアル付き。ご不明な点はお気軽にお問い合わせください。

お問い合わせ

microCMS公式アカウント

microCMSは各公式アカウントで最新情報をお届けしています。
フォローよろしくお願いします。

  • X
  • Discord
  • github

ABOUT ME

松田 承一
株式会社microCMSの代表 / 家族=👨‍👩‍👧 / ヤフー→大学教員など→現職 / 管理画面付きAPIがすぐに作れるmicroCMSというサービス作ってます。