目次
今回想定するケース
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
プロパティのvisible
・hidden
以外にも、opacity
プロパティの1
・0
、display
プロパティのblock
・none
でも表示・非表示の制御ができます。
visibility
・opacity
・display
の違いの詳細解説は【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 && expressio
nならexpression
、false && 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)やってます。フォローしてもらえるとうれしいです!