簡潔なReactコンポーネントを書くためのヒント

簡潔なReactコンポーネントを書くためのヒント

この記事は、翻訳された記事「きれいなReactコンポーネントを書くためのシンプルなヒント」に基づいています。元の著者はIskander Samatovです。

この記事では、よりクリーンな React コンポーネントを記述し、プロジェクトをより適切に拡張するのに役立ついくつかの簡単なテクニックを紹介します。

スプレッド演算子を使用してプロパティを渡すのは避けてください

まず、避けるべきアンチパターンから始めましょう。明確な理由がない限り、スプレッド演算子 (例: { ...props }) を使用してコンポーネント ツリーを介して props を渡すことは避けてください。

この方法でプロパティを渡すと、コンポーネントの記述が速くなります。しかし、これによりコード内のバグを見つけることも難しくなります。そうすると、作成したコンポーネントに対する信頼が失われ、コンポーネントのリファクタリングが困難になり、デバッグが困難なバグが発生する可能性があります。

関数パラメータをオブジェクトにカプセル化する

関数が複数のパラメータを受け入れる場合、それらをオブジェクトにカプセル化するのが最適です。例えば:

エクスポートconst sampleFunction = ({ param1, param2, param3 }) => {
  コンソールにログ出力します。
}

このように関数シグネチャを記述することには、いくつかの大きな利点があります。

  1. パラメータが渡される順序を気にする必要がなくなりました。関数パラメータが渡される順序が原因でバグを引き起こすミスをいくつか犯しました。
  2. スマートプロンプトが設定されたエディター(現在ほとんどのエディターに搭載されています)では、関数パラメータの自動補完が非常にうまく実行されます。

イベント処理関数の場合、処理関数を関数の戻り値として使用します。

関数型プログラミングに精通している場合、このプログラミング手法は、いくつかのパラメータが事前に設定されているため、関数のカリー化に似ていることがわかります。

次の例を見てみましょう。

'react' から React をインポートします

デフォルトの関数 SampleComponent({ onValueChange }) をエクスポートします。

  const handleChange = (キー) => {
    戻り値 (e) => onValueChange(キー、e.target.value)
  }

  戻る (
    <フォーム>
      <input onChange={handleChange('name')} />
      <input onChange={handleChange('email')} />
      <input onChange={handleChange('phone')} />
    </フォーム>
  )
}

ご覧のとおり、このようにハンドラー関数を記述すると、コンポーネント ツリーが簡潔になります。

コンポーネントのレンダリングではif/elseの代わりにマップを使用します

カスタム ロジックに基づいてさまざまな要素をレンダリングする必要がある場合は、if/else ステートメントの代わりに map を使用することをお勧めします。

以下は if/else を使用した例です。

'react' から React をインポートします

const Student = ({ name }) => <p>生徒名: {name}</p>
const Teacher = ({ name }) => <p>教師名: {name}</p>
const Guardian = ({ name }) => <p>ガーディアン名: {name}</p>

デフォルト関数 SampleComponent({ user }) をエクスポートします。
  コンポーネントを Student にします。
  if (user.type === '教師') {
    コンポーネント = 教師
  } それ以外の場合 (user.type === 'guardian') {
    コンポーネント = ガーディアン
  }

  戻る (
    <div>
      <コンポーネント名={user.name} />
    </div>
  )
}

以下は map を使用した例です。

'react' から React をインポートします

const Student = ({ name }) => <p>生徒名: {name}</p>
const Teacher = ({ name }) => <p>教師名: {name}</p>
const Guardian = ({ name }) => <p>ガーディアン名: {name}</p>

定数COMPONENT_MAP = {
  学生: 学生、
  先生:先生、
  ガーディアン: ガーディアン
}

デフォルト関数 SampleComponent({ user }) をエクスポートします。
  const コンポーネント = COMPONENT_MAP[user.type]

  戻る (
    <div>
      <コンポーネント名={user.name} />
    </div>
  )
}

この簡単な戦略を使用すると、コンポーネントをより読みやすく、理解しやすくすることができます。また、論理的な拡張も容易になります。

フックコンポーネント

このモードは、悪用されない限り非常に便利です。

アプリケーションでは多くのコンポーネントを使用することになる場合があります。機能するために状態が必要な場合は、その状態を提供するフックでラップできます。これらのコンポーネントの良い例としては、ポップアップ、トースト通知、シンプルなモーダル ダイアログなどがあります。たとえば、単純な確認ダイアログのフック コンポーネントを次に示します。

'react' から React をインポートします。{useCallback、useState }。
'components/global/ConfirmationDialog' から ConfirmationDialog をインポートします。

デフォルト関数 useConfirmationDialog({ をエクスポートする
  ヘッダーテキスト、
  本文、
  確認ボタンテキスト、
  確認クリック時、
}) {
  定数[isOpen, setIsOpen] = useState(false);

  定数 onOpen = () => {
    setIsOpen(true);
  };

  定数ダイアログ = useCallback(
    () => (
      <確認ダイアログ
        ヘッダーテキスト={ヘッダーテキスト}
        本文={本文}
        isOpen={isOpen}
        onConfirmClick={onConfirmClick}
        onCancelClick={() => setIsOpen(false)}
        確認ボタンテキスト={確認ボタンテキスト}
      />
    )、
    [開く]
  );

  戻る {
    ダイアログ、
    オープン時、
  };
}

フック コンポーネントは次のように使用できます。

「react」からReactをインポートします。
'./useConfirmationDialog' から { useConfirmationDialog } をインポートします。

関数クライアント() {
  const { ダイアログ、onOpen } = useConfirmationDialog({
    headerText: "このレコードを削除しますか?"
    本文:
      「このレコードを削除してもよろしいですか? 元に戻すことはできません。」
    確認ボタンテキスト:「削除」、
    onConfirmClick: handleDeleteConfirm、
  });

  関数handleDeleteConfirm() {
    //TODO: 削除
  }

  const handleDeleteClick = () => {
    オープン時();
  };

  戻る (
    <div>
      <ダイアログ />
      <ボタンのonClick={handleDeleteClick} />
    </div>
  );
}

デフォルトのクライアントをエクスポートします。

このようにコンポーネントを抽出すると、状態管理のために大量の定型コードを記述する必要がなくなります。 React フックについて詳しく知りたい場合は、私の投稿をご覧ください。

コンポーネントの分離

次の 3 つのヒントは、コンポーネントを巧みに分割する方法に関するものです。私の経験では、コンポーネントをシンプルに保つことが、プロジェクトを管理しやすくするための最善の方法です。

ラッパーの使用

複雑なコンポーネントを分解する方法を見つけるのに苦労している場合は、コンポーネントの各要素が提供する機能を確認してください。一部の要素は、ドラッグ アンド ドロップなどの独自の機能を提供します。

以下は react-beautiful-dnd を使用してドラッグ アンド ドロップを実装するコンポーネントの例です。

'react' から React をインポートします
'react-beautiful-dnd' から { DragDropContext, Droppable } をインポートします。
デフォルト関数DraggableSample()をエクスポートする{
  関数handleDragStart(結果) { 
    console.log({ 結果 });
  }
  関数handleDragUpdate({ destination }) { 
    console.log({ 宛先 });
  }
  const handleDragEnd = ({ ソース、 宛先 }) => { 
    console.log({ ソース、 宛先 });
  };
  戻る (
    <div>
      <ドラッグドロップコンテキスト
        onDragEnd={handleDragEnd}
        onDragStart={handleDragStart}
        onDragUpdate={handleDragUpdate}
      >
        <ドロップ可能 
          droppableId="ドロップ可能"
          方向="水平"
        >
          {(提供) => (
            <div {...provided.droppableProps} ref={provided.innerRef}> 
              {columns.map((列, インデックス) => {
                戻る (
                  <列コンポーネント
                    キー={インデックス}
                    列={列}
                  />
                );
              })}
            </div>
          )}
        </ドロップ可能>
      </ドラッグドロップコンテキスト>
    </div>
  )
}

次に、すべてのドラッグ ロジックをラッパーに移動した後のコンポーネントを見てみましょう。

'react' から React をインポートします
デフォルト関数DraggableSample()をエクスポートする{
  戻る (
    <div>
      <ドラッグラッパー> 
      {columns.map((列, インデックス) => { 
        戻る (
          <ColumnComponent キー = {インデックス} 列 = {列} />
        );
      })}
      </ドラッグラッパー>
    </div>
  )
}

ラッパーのコードは次のとおりです。

'react' から React をインポートします
'react-beautiful-dnd' から { DragDropContext, Droppable } をインポートします。
デフォルトの関数DragWrapper({children})をエクスポートします。
  関数handleDragStart(結果) { 
    console.log({ 結果 });
  }
  関数handleDragUpdate({ destination }) { 
    console.log({ 宛先 });
  }
  const handleDragEnd = ({ ソース、 宛先 }) => { 
    console.log({ ソース、 宛先 });
  };
  戻る (
    <ドラッグドロップコンテキスト 
      onDragEnd={handleDragEnd}
      onDragStart={handleDragStart} 
      onDragUpdate={handleDragUpdate}
    >
      <ドロップ可能 droppableId="ドロップ可能" direction="水平"> 
        {(提供) => (
          <div {...provided.droppableProps} ref={provided.innerRef}> 
            {子供たち}
          </div>
        )}
      </ドロップ可能>
    </ドラッグドロップコンテキスト>
  )
}

したがって、コンポーネントの機能をより高いレベルで確認する方が直感的になります。ドラッグのすべての機能はラッパー内にあるため、コードを理解しやすくなります。

関心の分離

これは、大きなコンポーネントを分解するための私のお気に入りの方法です。

React の観点から見ると、関心の分離とは、データの取得と変更を担当するコンポーネントの部分と、要素の表示のみを担当する部分を分離することを意味します。

この関心の分離がフックを導入する主な理由です。カスタム フックを使用して、すべてのメソッドまたはグローバル状態に接続されたロジックをカプセル化できます。

たとえば、次のコンポーネントを見てみましょう。

'react' から React をインポートします
'./API' から { someAPICall } をインポートします。 
'./ItemDisplay' から ItemDisplay をインポートします。
デフォルト関数SampleComponent()をエクスポートします。 
  const [データ、setData] = useState([])
  使用効果(() => { 
    someAPICall().then((結果) => { setData(結果)})
  }, [])
  関数 handleDelete() { console.log('削除!'); }
  関数 handleAdd() { console.log('追加!'); }
  const handleEdit = () => { console.log('編集!'); };
  戻る (
    <div>
      <div>
        {data.map(item => <ItemDisplay item={item} />)} 
      </div>
      <div>
        <ボタンのクリック={handleDelete} /> 
        <ボタンのクリック時={handleAdd} /> 
        <ボタン onClick={handleEdit} /> 
      </div>
    </div>
  )
}

以下は、カスタム フックによって分割されたコードを使用したリファクタリングされたバージョンです。

'react' から React をインポートします
'./ItemDisplay' から ItemDisplay をインポートします。
デフォルト関数SampleComponent()をエクスポートします。
  const { データ、handleDelete、handleEdit、handleAdd } = useCustomHook()
  戻る (
    <div>
      <div>
        {data.map(item => <ItemDisplay item={item} />)} 
      </div>
      <div>
        <ボタンのクリック={handleDelete} /> 
        <ボタンのクリック時={handleAdd} /> 
        <ボタン onClick={handleEdit} /> 
      </div>
    </div>
  )
}

フック自体のコードは次のとおりです。

'./API' から { someAPICall } をインポートします。
エクスポートconst useCustomHook = () => { 
  const [データ、setData] = useState([])
  使用効果(() => { 
    someAPICall().then((結果) => { setData(結果)})
  }, [])
  関数 handleDelete() { console.log('削除!'); }
  関数 handleAdd() { console.log('追加!'); }
  const handleEdit = () => { console.log('編集!'); };
  戻り値: { handleEdit、handleAdd、handleDelete、data }
}

各コンポーネントは個別のファイルとしてパッケージ化されています

通常、次のようなコードが書かれます。

'react' から React をインポートします
エクスポートデフォルト関数SampleComponent({データ}) {
  const ItemDisplay = ({名前、日付}) => ( 
    <div>
      <h3>{名前}</h3>
      <p>{日付}</p>
    </div> 
  )
  戻る (
    <div>
      <div>
        {data.map(item => <ItemDisplay item={item} />)}
      </div>
    </div> 
  )
}

React コンポーネントをこのように記述することに問題はありませんが、良い方法ではありません。 ItemDisplay コンポーネントを別のファイルに移動すると、コンポーネントが疎結合になり、拡張しやすくなります。

ほとんどの場合、クリーンで整然としたコードを書くには、適切なパターンに従い、アンチパターンを避けるように注意し、時間をかける必要があります。したがって、時間をかけてこれらのパターンに従うと、クリーンな React コンポーネントを作成するのに役立ちます。これらのパターンは私のプロジェクトで非常に役立っており、皆さんもそう感じていただければ幸いです。

以上が、簡潔なReactコンポーネントを書くためのヒントの詳細です。Reactコンポーネントを書くためのヒントの詳細については、123WORDPRESS.COMの他の関連記事に注目してください。

以下もご興味があるかもしれません:
  • Reactエラー境界コンポーネント処理
  • react setStateの詳細な説明
  • Reactはラジオコンポーネントのサンプルコードを実装します
  • React で setInterval 関数を使用する例
  • Andrew Ng の機械学習演習: SVM サポートベクターマシン

<<:  Dockerはdockerfileを使用してnode.jsアプリケーションを起動します

>>:  mysql 結合クエリ (左結合、右結合、内部結合)

推薦する

JavaScript で Priority Queue を実装する

目次1. 優先キューの紹介2. 優先キューのカプセル化1. 優先キューの紹介通常のキューに要素が挿入...

Nginx の高同時実行最適化の実践

1. チューニングの必要性​ 私は、どのように書けばいいのか本当に分からないので、共有するために最適...

Win10 64 ビットで圧縮パッケージを使用して最新の MySQL 8.0.18 をインストールするチュートリアル (画像とテキスト付き)

WIN10 64ビットに最新のMySQL8.0.18をインストールダウンロード公式サイトから最新バ...

Windows および Linux で tomcat9 を介して war パッケージを手動で展開する方法

Windows 環境と Linux 環境では結果が異なります。ウィンドウズステップ 1: Maven...

MySql のクラッシュとサービスの起動失敗の解決策

私は長い間PHPに触れてきましたが、インストール環境は非常に不慣れです。多くの問題に遭遇しました。B...

Spring jdbc のデータベース操作オブジェクト モデルの詳細な例

Spring jdbc のデータベース操作オブジェクト モデルの詳細な例Spring Jdbc デー...

航空機戦争ゲームを実装するためのネイティブJS

この記事の例では、参考のために航空機戦争ゲームを実装するためのJSの具体的なコードを共有しています。...

Docker 入門インストールチュートリアル (初心者版)

ドクター紹介: Docker はコンテナ関連の技術です。簡単に言うと、さまざまなソフトウェアを実行で...

vue フロントエンド HbuliderEslint リアルタイム検証 自動修復設定

目次HBuilderX での ESLint プラグインのインストールカスタム eslint-js ル...

node.jsミドルウェアの種類についての簡単な説明

目次概要1. アプリケーションレベルのミドルウェア2. 組み込みミドルウェア3. サードパーティミド...

MySQL 全体または単一のテーブルデータのエクスポート

単一のテーブルをエクスポートするmysqldump -u ユーザー -p db名 テーブル名 >...

ゲーム着物メモ問題の簡単な分析

本日、ゲームを再起動した後、バックアップしたデータをターゲットデータベースにインポートできないことが...

Vue.js プロジェクトの開始方法

目次1. Node.jsとVue 2. ローカル開発環境でフロントエンドのVueプロジェクトを実行す...

CSS3 のボックス サイズ設定 (コンテンツ ボックスとボーダー ボックス) の詳細な説明

CSS3 のボックス サイズ設定 (content-box と border-box) CSS3 の...

JS変数ストレージのディープコピーとシャローコピーの詳しい説明

目次可変タイプとストレージスペーススタックメモリとヒープメモリ基本的なデータ型参照タイプグラフィック...