【React】JSXにおけるコンポーネントの表示・非表示の制御方法まとめ

JavaScript

今回想定するケース

FormコンポーネントのローカルState(visible)の真偽値に応じて、Formコンポーネントから呼び出されるMessageコンポーネントの表示を制御する場合を考えます。

src/components/Form.tsx

import { useState, FC } from "react";
import { Message } from "src/components/Message";

export const Form: FC = () => {
  const [visible, setVisible] = useState(true);
  return (
    <>
      <Message visible={visible} />
      <button onClick={() => setVisible(!visible)}>
        {visible ? "hide" : "show"}
      </button>
    </>
  );
};

src/components/Message.tsx

import { FC } from "react";

type Props = {
  visible: boolean;
};

export const Message: FC<Props> = ({ visible }) => {
  return <>This is Message</>;
};

方法1: styleを直接記述する

例えば、要素の表示を制御するvisibilityプロパティの値を真偽値に応じて変更することでコンポーネントの表示・非表示を実現できます。

src/components/Message.tsx

import { FC } from "react";

type Props = {
  visible: boolean;
};

export const Message: FC<Props> = ({ visible }) => {
  return (
    <div style={{ visibility: visible ? "visible" : "hidden" }}>This is Message</div>
  );
};

visibilityプロパティのvisiblehidden以外にも、opacityプロパティの10displayプロパティのblocknoneでも表示・非表示の制御ができます。

visibilityopacitydisplayの違いの詳細解説は【CSS】display/visibility/opacityの比較・違いまとめで紹介しています。

方法2: classnames利用する

classnamesを利用すると条件に応じて適用するCSSを簡単に変更できます。

$ yarn add classnames
$ yarn add --dev @types/classnames

src/components/Message.tsx

import { FC } from "react";
import cx from "classnames";
import styles from "styles/Message.module.css";

type Props = {
  visible: boolean;
};

export const Message: FC<Props> = ({ visible }) => {
  return (
    <div className={cx(visible ? styles.visible : styles.hidden)}>
      This is Message
    </div>
  );
};

styles/Message.module.css

.visible {
  visibility: visible;
}

.hidden {
  visibility: hidden;
}

方法3: 非表示の場合はNULLを返す

非表示の際に要素(ここでいうMessageコンポーネント)をレイアウトから完全に消してよい、つまり要素の表示領域もなくしてよいのであれば、NULLを返すという方法もあります。

src/components/Message.tsx

import { FC } from "react";

type Props = {
  visible: boolean;
};

export const Message: FC<Props> = ({ visible }) => {
  if (!visible) return null;

  return <>This is Message</>;
};

参考: Emotionを使ってCSSを制御する方法

Emotionは比較的最近できたCSS in JSライブラリです。Emotionを利用すると以下のような記述ができます。

src/components/Message.tsx

import { FC } from "react";
import { css } from "@emotion/react";

type Props = {
  visible: boolean;
};

export const Message: FC<Props> = ({ visible }) => {
  return <div css={messageStyle(visible)}>This is Message</div>;
};

const messageStyle = (visible: boolean) =>
  css({
    visibility: visible ? "visible" : "hidden",
  });

Emotionの導入手順についてはEmotionをNext.js x TypeScriptの環境にインストールする手順で紹介しています。

参考: コンポーネント呼び出し側で表示・非表示を制御する方法

コンポーネントの呼び出し側(ここでいうFormコンポーネント)で表示の制御をする方法も紹介します。

方法1: &&演算子(論理積演算子、論理結合)を利用する方法

&&演算子(論理積演算子、論理結合)は true && expressionならexpressionfalse && expressionならfalseを返します。
&&演算子を利用することで『trueなら要素を表示、falseなら要素の存在を画面から完全に消す』を実現できます。

src/components/Form.tsx

import { useState, FC } from "react";
import { Message } from "src/components/Message";

export const Form: FC = () => {
  const [visible, setVisible] = useState(true);
  return (
    <>
      {visible && <Message />}
      <button onClick={() => setVisible(!visible)}>
        {visible ? "hide" : "show"}
      </button>
    </>
  );
};

&&演算子(論理積演算子、論理結合)の活用事例については【React】JSXでif文を利用して要素を出し分ける(条件付きレンダー)方法で紹介しています。

方法2: styleを直接記述する

src/components/Form.tsx

import { useState, FC } from "react";
import { Message } from "src/components/Message";

export const Form: FC = () => {
  const [visible, setVisible] = useState(true);
  return (
    <>
      <div style={{ visibility: visible ? "visible" : "hidden" }}>
        <Message />
      </div>
      <button onClick={() => setVisible(!visible)}>
        {visible ? "hide" : "show"}
      </button>
    </>
  );
};

方法3: classnames利用する

src/components/Form.tsx

import { useState, FC } from "react";
import { Message } from "src/components/Message";
import styles from "styles/Form.module.css";
import cx from "classnames";

export const Form: FC = () => {
  const [visible, setVisible] = useState(true);
  return (
    <>
      <div className={cx(visible ? styles.visible : styles.hidden)}>
        <Message />
      </div>
      <button onClick={() => setVisible(!visible)}>
        {visible ? "hide" : "show"}
      </button>
    </>
  );
};

styles/Form.module.css

.visible {
  visibility: visible;
}

.hidden {
  visibility: hidden;
}

さいごに

Twitter(@nishina555)やってます。フォローしてもらえるとうれしいです!