Reactアプリケーションで条件付きレンダリングを実装する7つの方法
序章
動的でReactとの高度なインタラクティブ性を備えたシングルページアプリケーション(SPA)を構築できます。 これを可能にする1つの機能は、条件付きレンダリングです。
条件付きレンダリングは、条件がtrueまたはfalseの場合に、さまざまなユーザーインターフェイス(UI)マークアップをレンダリングする機能を表す用語です。 Reactでは、条件に基づいてさまざまな要素やコンポーネントをレンダリングできます。 この概念は、次のシナリオでよく適用されます。
- APIからの外部データのレンダリング。
- 要素の表示または非表示。
- アプリケーション機能の切り替え。
- 権限レベルの実装。
- 認証と承認の処理。
この記事では、Reactアプリケーションで条件付きレンダリングを実装する7つの方法を検討します。
前提条件
このチュートリアルを完了するには、次のものが必要です。
- JavaScriptの変数と関数の理解。 詳細については、JavaScriptでコーディングする方法シリーズを参照してください。
- Reactコンポーネントのインポート、エクスポート、およびレンダリングに関する理解。 React.jsシリーズのコーディング方法を確認できます。
- Node.jsはローカルにインストールされます。これは、Node.jsのインストール方法とローカル開発環境の作成に従って実行できます。
このチュートリアルは、Node v15.6.0、npm v7.4.0、およびreact
v17.0.1で検証されました。
サンプルプロジェクトの設定
ユーザーがログインする必要があるアプリケーションについて考えてみます。 ユーザーがログアウトすると、ログインボタンが表示されます。 ユーザーがログインしている場合は、ログアウトボタンが表示されます。
create-react-appを使用してReactアプリを生成することから始めます。
- npx create-react-app react-conditional-rendering-example
新しいプロジェクトディレクトリに移動します。
- cd react-conditional-rendering-example
次に、コードエディタでApp.js
ファイルを開きます。 そして、内容を次のコード行に置き換えます。
import React, { Component } from "react";
import './App.css';
class App extends Component {
constructor(props) {
super(props);
this.state = {
isLoggedIn: true
};
}
render() {
return (
<div className="App">
<h1>
This is a Demo showing several ways to implement Conditional Rendering in React.
</h1>
<button>Login</button>
<button>Logout</button>
</div>
);
}
}
export default App;
次に、コードエディタでApp.css
ファイルを開きます。 そして、内容を次のコード行に置き換えます。
body {
padding: 1em;
}
h1 {
font-size: 3em;
font-weight: 500;
text-align: center;
margin-bottom: 1em;
margin-right: 1em;
padding: 0;
}
button {
appearance: none;
background-color: #246bec;
border: 1px solid #246bec;
border-radius: 0;
box-sizing: border-box;
color: #ffffff;
display: block;
font-size: 2em;
font-weight: 500;
margin-bottom: 1em;
margin-top: 1em;
padding: .5em;
width: 100%;
transition: border-color, background-color 300ms ease-in-out;
}
button:focus {
border-color: #00006D;
}
button:hover {
background-color: #0B52D3;
}
button:active {
background-color: #00006D;
}
次に、ターミナルウィンドウからアプリケーションを実行します。
- npm start
そして、ブラウザでアプリケーションを操作します。
各条件付きレンダリングアプローチは、このコードに基づいて構築されます。 この時点でgit commit
を作成して、このチュートリアルを進めながら変更をロールバックすることをお勧めします。
この時点で、ログインボタンとログアウトボタンを表示するReactアプリケーションが作成されます。 あなたの目標は、これらのボタンの1つだけを表示させることです。 これを実現するための条件付きレンダリングアプローチを見てみましょう。
1. if…else
ステートメントの使用
if…else
ステートメントは、条件が満たされたときにif
ブロックに含まれるアクションを実行します。 それ以外の場合は、else
ブロックに含まれるアクションを実行します。
JSXでは、マークアップ付きのJavaScriptコードを使用して、アプリケーション内で動的な値をレンダリングできます。 JSXは、中括弧({
および}
)を使用して、レンダリング前に解釈する必要のある式を示します。 ただし、注意点は、そのような中括弧内で実行できることには制限があるということです。
render()
メソッドでif…else
ステートメントを使用しようとしたかどうかを考えてみましょう。
警告:これは正しく機能しないコードの例です。 これは、render()
メソッドでの解釈の制限の例として示されています。
// ...
class App extends Component {
// ...
render() {
let {isLoggedIn} = this.state;
return (
<div className="App">
<h1>
This is a Demo showing several ways to implement Conditional Rendering in React.
</h1>
{
if(isLoggedIn){
return <button>Logout</button>
} else{
return <button>Login</button>
}
}
</div>
);
}
}
// ...
このコードはUnexpected token
エラーを生成します。 ロジックはrender()
メソッドの外に移動する必要があります。
コードエディタでApp.js
ファイルを開き、render()
メソッドまで下にスクロールして、次の強調表示されたコード変更を行います。
// ...
class App extends Component {
// ...
render() {
let {isLoggedIn} = this.state;
const renderAuthButton = () => {
if (isLoggedIn) {
return <button>Logout</button>;
} else {
return <button>Login</button>;
}
}
return (
<div className="App">
<h1>
This is a Demo showing several ways to implement Conditional Rendering in React.
</h1>
{renderAuthButton()}
</div>
);
}
}
// ...
これは、抽出された関数を作成するプロセスです。 このコードは、JSXから関数renderAuthButton
にロジックを抽出します。 そして、関数はJSX中括弧内で実行されます。
Webブラウザでアプリケーションを開きます。 以前は、ログインボタンとログアウトボタンが表示されていました。 これで、isLoggedIn
状態はtrue
になり、条件付きロジックではログアウトボタンのみが表示されます。
ここで、代わりにrender()
メソッドで複数のreturn
を使用しようとしたかどうかを考えてみましょう。
警告:これは、パフォーマンスの低いコードの例であり、避ける必要があります。
// ...
class App extends Component {
// ...
render() {
let {isLoggedIn} = this.state;
if (isLoggedIn) {
return (
<div className="App">
<h1>
This is a Demo showing several ways to implement Conditional Rendering in React.
</h1>
<button>Logout</button>
</div>
);
} else {
return (
<div className="App">
<h1>
This is a Demo showing several ways to implement Conditional Rendering in React.
</h1>
<button>Login</button>
</div>
);
}
}
}
// ...
上記のスニペットは同じ結果を達成しますが、変更されていないコンポーネントを絶えず再レンダリングした結果としてパフォーマンスの問題が発生する一方で、コンポーネントが不必要に肥大化します。
ベストプラクティスは、兄弟または親コンポーネントの無駄な再レンダリングを回避するために、コンポーネントを可能な限り単純に保つことです。
コードエディタで、新しいAuthButton.js
ファイルを作成します。
import React from "react";
const AuthButton = props => {
let { isLoggedIn } = props;
if (isLoggedIn) {
return <button>Logout</button>;
} else {
return <button>Login</button>;
}
};
export default AuthButton;
AuthButton
は、isLoggedIn
プロップを介して渡される状態の値に応じて、さまざまな要素またはコンポーネントを返します。
次に、App.js
に再度アクセスし、新しいコンポーネントを使用するように変更します。
import React, { Component } from "react";
import './App.css';
import AuthButton from "./AuthButton";
class App extends Component {
constructor(props) {
super(props);
this.state = {
isLoggedIn: true
};
}
render() {
return (
<div className="App">
<h1>
This is a Demo showing several ways to implement Conditional Rendering in React.
</h1>
<AuthButton isLoggedIn={isLoggedIn} />
</div>
);
}
}
export default App;
これは、抽出された機能コンポーネントを作成するプロセスです。 このコードは、renderAuthButton()
アプローチと同じ結果を生成します。 ただし、変更を別のコンポーネントに移動するという利点があります。
2. switch
ステートメントの使用
前に示したように、if…else
ステートメントを使用して、設定された条件に基づいてコンポーネントから条件付きで異なるマークアップを返すことができます。 同じことは、さまざまな条件のマークアップを指定できるswitch
ステートメントでも実現できます。
AuthButton
コンポーネントを再検討し、if…else
ステートメントをswitch
ステートメントに置き換えます。
import React from "react";
const AuthButton = props => {
let { isLoggedIn } = props;
switch (isLoggedIn) {
case true:
return <button>Logout</button>;
break;
case false:
return <button>Login</button>;
break;
default:
return null;
}
};
export default AuthButton;
このコードがisLoggedIn
の値に基づいてさまざまなボタンを返す方法に注目してください。
注: 3つ以上の可能な値または結果がある場合は、switch
ステートメントメソッドを適用する方が実用的です。
さらに、コンポーネントからnull
を返すと、コンポーネントは非表示になります(何も表示されません)。 これは、コンポーネントの表示を切り替える良い方法です。
3. 要素変数の使用
要素変数は、条件付きレンダリングを関数に抽出するアプローチに似ています。 要素変数は、JSX要素を保持する変数です。 JSXの外部でこれらの変数に要素またはコンポーネントを条件付きで割り当て、JSX内でのみ変数をレンダリングできます。
アプリケーションは次のように書き直すことができます。
import React, { Component } from "react";
import './App.css';
class App extends Component {
constructor(props) {
super(props);
this.state = {
isLoggedIn: true
};
}
render() {
let { isLoggedIn } = this.state;
let AuthButton;
if (isLoggedIn) {
AuthButton = <button>Logout</button>;
} else {
AuthButton = <button>Login</button>;
}
return (
<div className="App">
<h1>
This is a Demo showing several ways to implement Conditional Rendering in React.
</h1>
{AuthButton}
</div>
);
}
}
export default App;
このコードが条件付きで値(コンポーネント)をAuthButton
に割り当て、後でJSXで参照できることに注意してください。
4. 三項演算子の使用
条件付き(三項)演算子は、3つのオペランドをとる唯一のJavaScript演算子です。 この演算子は、if
ステートメントのショートカットとして頻繁に使用されます。
アプリケーションは次のように書き直すことができます。
import React, { Component } from "react";
import './App.css';
class App extends Component {
constructor(props) {
super(props);
this.state = {
isLoggedIn: true
};
}
render() {
let { isLoggedIn } = this.state;
return (
<div className="App">
<h1>
This is a Demo showing several ways to implement Conditional Rendering in React.
</h1>
{isLoggedIn ? <button>Logout</button> : <button>Login</button>}
</div>
);
}
}
export default App;
このアプローチにより、コンポーネントが肥大化したり、かさばったり、読みにくくなったりする場合は、機能コンポーネント内に条件をカプセル化できます。
import React from "react";
const AuthButton = props => {
let { isLoggedIn } = props;
return isLoggedIn ? <button>Logout</button> : <button>Login</button>;
};
export default AuthButton;
三項アプローチは、複雑でないif…else
評価に役立ちます。 複雑な比較やコンポーネントの場合、プロジェクトが成長するにつれて読みやすさに影響を与える可能性があります。
5. 論理&&
の使用(短絡評価)
短絡評価は、式のオペランドの評価中に副作用がないことを確認するために使用される手法です。 論理&&
は、アクションが1つの条件でのみ実行されるように指定するのに役立ちます。そうでない場合、アクションは完全に無視されます。
アプリケーションは次のように書き直すことができます。
import React, { Component } from "react";
import './App.css';
class App extends Component {
constructor(props) {
super(props);
this.state = {
isLoggedIn: true
};
}
render() {
let { isLoggedIn } = this.state;
return (
<div className="App">
<h1>
This is a Demo showing several ways to implement Conditional Rendering in React.
</h1>
{isLoggedIn && <button>Logout</button>}
</div>
);
}
}
export default App;
このコードは、isLoggedIn
がtrue
の場合、ログアウトボタンを表示します。それ以外の場合は、何も表示しません。
次に、Loginボタンに2番目の短絡評価を使用することを検討しましょう。
警告:これは、パフォーマンスの低いコードの例であり、避ける必要があります。
{isLoggedIn && <button>Logout</button>}
{!isLoggedIn && <button>Login</button>}
このコードは、isLoggedIn
の値に基づいて右ボタンをレンダリングします。 ただし、同じ効果を達成するためのより優れた、よりクリーンな方法があるため、これはお勧めしません。 アプリケーションが大きくなるにつれて、この短絡評価の乱用は煩雑で直感的でないものになる可能性があります。
6. 即時呼び出し関数式(IIFE)の使用
前のセクションでは、JSXの制限により、すべてのタイプのJavaScriptコードを実行できないと述べました。 即時呼び出し関数式(IFFE)を使用すると、これらの制限を回避できます。 IFFEは、定義されるとすぐに実行されるJavaScript関数です。
(function () {
// statements
})();
この手法を使用すると、JSX内で直接条件付きロジックを記述できますが、そのコードの評価時にすぐに呼び出される無名関数内にラップされます。
アプリケーションは次のように書き直すことができます。
import React, { Component } from "react";
import './App.css';
class App extends Component {
constructor(props) {
super(props);
this.state = {
isLoggedIn: true
};
}
render() {
let { isLoggedIn } = this.state;
return (
<div className="App">
<h1>
This is a Demo showing several ways to implement Conditional Rendering in React.
</h1>
{(function() {
if (isLoggedIn) {
return <button>Logout</button>;
} else {
return <button>Login</button>;
}
})()}
</div>
);
}
}
export default App;
これは、矢印関数を使用してもう少し簡潔に記述することもできます。
{(() => {
if (isLoggedIn) {
return <button>Logout</button>;
} else {
return <button>Login</button>;
}
})()}
IIFEの詳細については、MDNを参照してください。
7. 拡張JSXライブラリの使用
特定のライブラリは、JSXを拡張する機能を公開し、JSXを使用して条件付きレンダリングを直接実装できるようにします。 そのようなライブラリの1つは、JSX制御ステートメントです。 これはBabelプラグインであり、変換中にコンポーネントのような制御ステートメントを対応するJavaScriptステートメントに変換します。
babel-plugin-jsx-control-statements
パッケージをインストールし、Babel構成を変更した後、アプリケーションは次のように書き直すことができます。
import React, { Component } from "react";
import './App.css';
class App extends Component {
constructor(props) {
super(props);
this.state = {
isLoggedIn: true
};
}
render() {
let { isLoggedIn } = this.state;
return (
<div className="App">
<h1>
This is a Demo showing several ways to implement Conditional Rendering in React.
</h1>
<Choose>
<When condition={isLoggedIn}>
<button>Logout</button>;
</When>
<When condition={!isLoggedIn}>
<button>Login</button>;
</When>
</Choose>
</div>
);
}
}
export default App;
ただし、作成したコードは最終的に通常のJavaScript条件付きにトランスパイルされるため、このアプローチはお勧めしません。 些細なことに依存関係を追加するよりも、JavaScriptを作成する方が常に良いでしょう。
条件付きレンダリングアプローチの選択
原則として、条件付きレンダリングを実装する際には、次のことを確認するのが最善です。
- コンポーネントが不必要にアンマウントおよび再マウントされるのを防ぐために、コンポーネントの位置を任意に変更しないでください。
- 条件付きレンダリングに関係するマークアップのみを変更します。
render
メソッド内でコンポーネントを不必要に肥大化させないでください。これにより、コンポーネントのレンダリングが遅延します。
詳細については、ColeWilliamsによるReactの高性能条件に関するこの記事を参照してください。
考慮すべき事項は次のとおりです。
- 条件付きでレンダリングされるマークアップのサイズ
- 考えられる結果の数
- どちらがより直感的で読みやすいでしょう
一般に、次の推奨事項に留意してください。
- 期待される結果が1つしかない状況では、「短絡評価」がおそらく最も適切です。
- 2つの予想される結果がある状況では、
if…else
ステートメント、要素変数、三項演算子、または「即時呼び出し関数式」がおそらく最も適切です。 - 3つ以上の結果がある状況では、
switch
ステートメント、抽出された関数、または抽出された関数コンポーネントがおそらく最も適切です。
これらは推奨事項であり、規則ではないことに注意してください。 プロジェクトのニーズと慣習により、これらの推奨事項に従わないアプローチを採用する必要がある場合があります。
結論
この記事では、Reactアプリケーションで条件付きレンダリングを実装する7つの方法を検討しました。 それぞれの方法には独自の利点があり、どちらを使用するかの選択は主にユースケースに依存します。
詳細については、条件付きレンダリングのドキュメントを参照してください。
高次コンポーネントおよびHOCを使用した条件付きレンダリングで学習を続けてください。