小道具と反応してラッパーコンポーネントを作成する方法
著者は、 Creative Commons を選択して、 Write forDOnationsプログラムの一環として寄付を受け取りました。
序章
このチュートリアルでは、 React JavaScriptライブラリを使用して、小道具を使用してラッパーコンポーネントを作成します。 ラッパーコンポーネントは、不明なコンポーネントを囲むコンポーネントであり、子コンポーネントを表示するためのデフォルトの構造を提供します。 このパターンは、モーダル、テンプレートページ、情報タイルなど、デザイン全体で繰り返し使用されるユーザーインターフェイス(UI)要素を作成する場合に役立ちます。
ラッパーコンポーネントを作成するには、最初にRESTおよびSpread演算子を使用して未使用の小道具を収集し、ネストされたコンポーネントに渡す方法を学習します。 次に、組み込みのchildren
コンポーネントを使用して、ネストされたコンポーネントをHTML要素であるかのようにJSXにラップするコンポーネントを作成します。 最後に、コンポーネントを小道具として渡して、コンポーネント内の複数の場所にカスタムJSXを埋め込むことができる柔軟なラッパーを作成します。
チュートリアルでは、動物データのリストをカードの形式で表示するコンポーネントを作成します。 柔軟なラッピングコンポーネントを作成しながら、データを分割してコンポーネントをリファクタリングする方法を学びます。 このチュートリアルを終了すると、高度なプロップ技術を使用して、アプリケーションの成長と変化に応じて拡張および適応する再利用可能なコンポーネントを作成する、実用的なアプリケーションが完成します。
注:最初のステップでは、チュートリアル演習を作成するための空白のプロジェクトを設定します。 すでに作業中のプロジェクトがあり、小道具の操作に直接進みたい場合は、ステップ2から始めてください。
前提条件
- Node.jsを実行する開発環境が必要になります。 このチュートリアルは、Node.jsバージョン10.20.1およびnpmバージョン6.14.4でテストされました。 これをmacOSまたはUbuntu18.04にインストールするには、Node.jsをインストールしてmacOSにローカル開発環境を作成する方法またはのPPAを使用したインストール]セクションの手順に従います。 Ubuntu18.04にNode.jsをインストールする方法。
- このチュートリアルでは、 Create ReactAppを使用してアプリを作成します。 Create React Appを使用してアプリケーションをインストールする手順と、その動作に関する一般的な情報については、 CreateReactAppを使用してReactプロジェクトをセットアップする方法を参照してください。
- Reactコンポーネントを使用します。これについては、Reactチュートリアルでカスタムコンポーネントを作成する方法で学ぶことができます。 また、小道具を使用してReactコンポーネントをカスタマイズする方法で学ぶことができる、React小道具の基本的な理解を深めるのにも役立ちます。
- また、JavaScriptの基本的な知識も必要です。これは、 JavaScriptでコーディングする方法シリーズにあり、HTMLとCSSの基本的な知識もあります。 HTMLとCSSの優れたリソースは、 Mozilla DeveloperNetworkです。
ステップ1—空のプロジェクトを作成する
このステップでは、 Create ReactAppを使用して新しいプロジェクトを作成します。 次に、プロジェクトをブートストラップするときにインストールされるサンプルプロジェクトと関連ファイルを削除します。 最後に、コンポーネントを整理するための単純なファイル構造を作成します。 これにより、次のステップでこのチュートリアルのラッパーアプリケーションを構築するための確固たる基盤が得られます。
まず、新しいプロジェクトを作成します。 コマンドラインで次のスクリプトを実行し、create-react-app
を使用して新しいプロジェクトをインストールします。
npx create-react-app wrapper-tutorial
プロジェクトが終了したら、次のディレクトリに移動します。
cd wrapper-tutorial
新しいターミナルタブまたはウィンドウで、 CreateReactApp開始スクリプトを使用してプロジェクトを開始します。 ブラウザは変更時に自動更新されるため、作業中はこのスクリプトを実行したままにします。
npm start
実行中のローカルサーバーを取得します。 プロジェクトがブラウザウィンドウで開かなかった場合は、 http:// localhost:3000/でプロジェクトを開くことができます。 これをリモートサーバーから実行している場合、アドレスはhttp://your_domain:3000
になります。
ブラウザには、CreateReactAppの一部として含まれている単純なReactアプリケーションが読み込まれます。
完全に新しいカスタムコンポーネントのセットを構築するので、空のプロジェクトを作成できるように、ボイラープレートコードをクリアすることから始める必要があります。
まず、テキストエディタでsrc/App.js
を開きます。 これは、ページに挿入されるルートコンポーネントです。 すべてのコンポーネントはここから始まります。 App.js
の詳細については、 Create ReactAppを使用してReactプロジェクトをセットアップする方法を参照してください。
次のコマンドでsrc/App.js
を開きます。
nano src/App.js
次のようなファイルが表示されます。
ラッパー-tutorial/src / App.js
import React from 'react'; import logo from './logo.svg'; import './App.css'; function App() { return ( <div className="App"> <header className="App-header"> <img src={logo} className="App-logo" alt="logo" /> <p> Edit <code>src/App.js</code> and save to reload. </p> <a className="App-link" href="https://reactjs.org" target="_blank" rel="noopener noreferrer" > Learn React </a> </header> </div> ); } export default App;
import logo from './logo.svg';
の行を削除します。 次に、return
ステートメントのすべてを置き換えて、空のタグのセット<></>
を返します。 これにより、何も返さない有効なページが表示されます。 最終的なコードは次のようになります。
ラッパー-tutorial/src / App.js
import React from 'react'; import './App.css'; function App() { return <></>; } export default App;
テキストエディタを保存して終了します。
最後に、ロゴを削除します。 アプリケーションで使用することはないので、作業中に未使用のファイルを削除する必要があります。 長期的には混乱からあなたを救うでしょう。
ターミナルウィンドウで、次のコマンドを入力します。
rm src/logo.svg
ブラウザを見ると、空白の画面が表示されます。
サンプルのCreateReactAppプロジェクトをクリアしたので、単純なファイル構造を作成します。 これにより、コンポーネントを分離して独立させることができます。
src
ディレクトリにcomponents
というディレクトリを作成します。 これにより、すべてのカスタムコンポーネントが保持されます。
mkdir src/components
各コンポーネントには、スタイル、存在する場合は画像、およびテストとともにコンポーネントファイルを保存するための独自のディレクトリがあります。
App
のディレクトリを作成します。
mkdir src/components/App
すべてのApp
ファイルをそのディレクトリに移動します。 ワイルドカード*
を使用して、ファイル拡張子に関係なく、App.
で始まるファイルを選択します。 次に、mv
コマンドを使用して、それらを新しいディレクトリに配置します。
mv src/App.* src/components/App
次に、index.js
の相対インポートパスを更新します。これは、プロセス全体をブートストラップするルートコンポーネントです。
nano src/index.js
importステートメントは、App
ディレクトリのApp.js
ファイルを指す必要があるため、次の強調表示された変更を行います。
ラッパー-tutorial/src / index.js
import React from 'react'; import ReactDOM from 'react-dom'; import './index.css'; import App from './components/App/App'; import * as serviceWorker from './serviceWorker'; ReactDOM.render( <React.StrictMode> <App /> </React.StrictMode>, document.getElementById('root') ); // If you want your app to work offline and load faster, you can change // unregister() to register() below. Note this comes with some pitfalls. // Learn more about service workers: https://bit.ly/CRA-PWA serviceWorker.unregister();
ファイルを保存して終了します。
プロジェクトが設定されたので、最初のコンポーネントを作成できます。
ステップ2—...props
を使用して未使用の小道具を収集する
このステップでは、動物のグループに関するデータのセットを表示するコンポーネントを作成します。 コンポーネントには、情報を視覚的に表示するための2番目のネストされたコンポーネントが含まれます。 親とネストされたコンポーネントを接続するには、RESTおよびSpread演算子を使用して、親が小道具の名前や種類を意識することなく、未使用の小道具を親から子に渡します。
このステップの終わりまでに、小道具が何であるかを知らなくても、ネストされたコンポーネントに小道具を提供できる親コンポーネントができあがります。 これにより、親コンポーネントが柔軟に保たれ、親を変更せずに子コンポーネントを更新できるようになります。
AnimalCard
コンポーネントの作成
まず、動物のデータセットを作成します。 まず、components/App
ディレクトリにあるデータセットを含むファイルを開きます。
nano src/components/App/data.js
次のデータを追加します。
src / components / App / data.js
export default [ { name: 'Lion', scientificName: 'Panthero leo', size: 140, diet: ['meat'] }, { name: 'Gorilla', scientificName: 'Gorilla beringei', size: 205, diet: ['plants', 'insects'] }, { name: 'Zebra', scientificName: 'Equus quagga', size: 322, diet: ['plants'], } ]
この動物のリストは、オブジェクトの配列であり、動物の名前、学名、体重、および食事が含まれています。
ファイルを保存して閉じます。
次に、AnimalCard
コンポーネントのディレクトリを作成します。
mkdir src/components/AnimalCard
ディレクトで新しいファイルを開きます。
nano src/components/AnimalCard/AnimalCard.js
次に、name
、diet
、およびsize
を小道具として使用するコンポーネントを追加し、それを表示します。
ラッパー-tutorial/src / components / AnimalCard / AnimalCard.js
import React from 'react'; import PropTypes from 'prop-types'; export default function AnimalCard({ diet, name, size }) { return( <div> <h3>{name}</h3> <div>{size}kg</div> <div>{diet.join(', ')}.</div> </div> ) } AnimalCard.propTypes = { diet: PropTypes.arrayOf(PropTypes.string).isRequired, name: PropTypes.string.isRequired, size: PropTypes.number.isRequired, }
ここでは、AnimalCard
関数のパラメーターリストにある小道具を破壊し、div
にデータを表示しています。 diet
データは、 join()メソッドを使用して単一の文字列としてリストされます。 各データには、データ型が正しいことを確認するために、対応するPropTypeが含まれています。
ファイルを保存して閉じます。
コンポーネントとデータが揃ったので、それらを組み合わせる必要があります。 これを行うには、コンポーネントとデータをプロジェクトのルートコンポーネントApp.js
にインポートします。
まず、コンポーネントを開きます。
nano src/components/App/App.js
そこから、データをループして、関連する小道具を含む新しいAnimalCard
を返すことができます。 強調表示された行をApp.js
に追加します。
ラッパー-tutorial/src / components / App / App.js
import React from 'react'; import './App.css'; import animals from './data'; import AnimalCard from '../AnimalCard/AnimalCard'; function App() { return ( <div className="wrapper"> {animals.map(animal => <AnimalCard diet={animal.diet} key={animal.name} name={animal.name} size={animal.size} /> )} </div> ); } export default App;
ファイルを保存して閉じます。
より複雑なプロジェクトで作業する場合、データは API 、 localStorage 、静的ファイルなど、より多様な場所から取得されます。 ただし、これらのそれぞれを使用するプロセスは似ています。データを変数に割り当て、データをループします。 この場合、データは静的ファイルからのものであるため、変数に直接インポートしています。
このコードでは、 .map()メソッドを使用して、animals
を反復処理し、小道具を表示します。 すべてのデータを使用する必要はないことに注意してください。 たとえば、scientificName
プロパティを明示的に渡していない。 また、Reactがマップされたデータを追跡するために使用する別のkey
小道具を追加しています。 最後に、スタイリングを追加するために使用するwrapper
のclassName
を使用して、コードをdiv
でラップします。
このスタイルを追加するには、App.css
を開きます。
nano src/components/App/App.css
ボイラープレートのスタイルを削除し、flexプロパティをwrapper
というクラスに追加します。
prop-tutorial / src / components / App / App.css
.wrapper { display: flex; flex-wrap: wrap; justify-content: space-between; padding: 20px; }
これは、フレックスボックスレイアウトを使用してデータを整理し、データが整列するようにします。 padding
はブラウザウィンドウにいくらかのスペースを与え、justify-content
は要素間の余分なスペースを広げます。
ファイルを保存して終了します。 これを行うと、ブラウザが更新され、一部のデータが間隔を空けて表示されます。
詳細コンポーネントの作成
これで、データを表示する単純なコンポーネントができました。 ただし、テキストを絵文字に変換して、diet
データに少しセンスを加えたいとしましょう。 これを行うには、コンポーネントのデータを変換します。
Reactは柔軟に設計されているため、データを変換する方法を考えるときは、いくつかの異なるオプションがあります。
- コンポーネント内に、テキストを絵文字に変換する関数を作成できます。
- 関数を作成してコンポーネント外のファイルに保存すると、さまざまなコンポーネント間でロジックを再利用できます。
- テキストを絵文字に変換する別のコンポーネントを作成できます。
それぞれのアプローチは、適切なユースケースに適用すれば問題なく、アプリケーションを構築するときにそれらを切り替えることができます。 時期尚早の抽象化と複雑さを回避するには、最初のオプションを使用して開始する必要があります。 ロジックを再利用したい場合は、コンポーネントとは別に関数を引き出すことができます。 3番目のオプションは、ロジックとマークアップを含む再利用可能な部分が必要な場合、またはアプリケーション全体で使用するために分離したい場合に最適です。
この場合、後でデータを追加する必要があり、マークアップと変換ロジックを組み合わせているため、新しいコンポーネントを作成します。
新しいコンポーネントはAnimalDetails
と呼ばれます。 これを作成するには、新しいディレクトリを作成します。
mkdir src/components/AnimalDetails
次に、テキストエディタでAnimalDetails.js
を開きます。
nano src/components/AnimalDetails/AnimalDetails.js
ファイル内に、diet
を絵文字として表示する小さなコンポーネントを作成します。
ラッパー-チュートリアル/src/components/AnimalDetails/AnimalDetails.js
import React from 'react'; import PropTypes from 'prop-types'; import './AnimalDetails.css'; function convertFood(food) { switch(food) { case 'insects': return '🐜'; case 'meat': return '🍖'; case 'plants': default: return '🌱'; } } export default function AnimalDetails({ diet }) { return( <div className="details"> <h4>Details:</h4> <div> Diet: {diet.map(food => convertFood(food)).join(' ')} </div> </div> ) } AnimalDetails.propTypes = { diet: PropTypes.arrayOf(PropTypes.string).isRequired, }
AnimalDetails.propTypes
オブジェクトは、文字列の配列であるdiet
の小道具を取る関数を設定します。 次に、コンポーネント内で、コードはdiet
をループし、switchステートメントを使用して文字列を絵文字に変換します。
ファイルを保存して閉じます。
CSSもインポートしているので、ここで追加しましょう。
AnimalDetails.css
を開きます:
nano src/components/AnimalDetails/AnimalDetails.css
CSSを追加して、要素に境界線と余白を付け、コンポーネントの残りの部分から詳細を分離します。
ラッパー-チュートリアル/src/components/AnimalDetails/AnimalDetails.css
.details { border-top: gray solid 1px; margin: 20px 0; }
.details
を使用して、details
のclassName
を持つ要素にルールを一致させます。
ファイルを保存して閉じます。
新しいカスタムコンポーネントができたので、それをAnimalCard
コンポーネントに追加できます。 AnimalCard.js
を開きます:
nano src/components/AnimalCard/AnimalCard.js
diet.join
ステートメントを新しいAnimalDetails
コンポーネントに置き換え、強調表示された行を追加して、diet
を小道具として渡します。
ラッパー-tutorial/src / components / AnimalCard / AnimalCard.js
import React from 'react'; import PropTypes from 'prop-types'; import AnimalDetails from '../AnimalDetails/AnimalDetails'; export default function AnimalCard({ diet, name, size }) { return( <div> <h3>{name}</h3> <div>{size}kg</div> <AnimalDetails diet={diet} /> </div> ) } AnimalCard.propTypes = { diet: PropTypes.arrayOf(PropTypes.string).isRequired, name: PropTypes.string.isRequired, size: PropTypes.number.isRequired, }
ファイルを保存すると、ブラウザに新しい詳細が表示されます。
...props
を使用してコンポーネントを介して詳細を渡す
コンポーネントは一緒にうまく機能していますが、AnimalCard
にはわずかな非効率性があります。 props
引数からdiet
を明示的に引き出していますが、データを使用していません。 代わりに、それをコンポーネントに渡します。 これについて本質的に悪いことは何もありません。実際、コミュニケーションが多すぎるという側面で誤りを犯したほうがよい場合がよくあります。 ただし、これを行うと、コードの保守がより困難になります。 新しいデータをAnimalDetails
に渡す場合は常に、小道具を渡すApp
、小道具を消費するAnimalDetails
、AnimalCard
、これは仲介役です。
より良い方法は、AnimalCard
内に未使用の小道具を集めて、それらをAnimalDetails
に直接渡すことです。 これにより、AnimalCard
を変更せずに、AnimalDetails
に変更を加えることができます。 実際、AnimalCard
は、AnimalDetails
に入る小道具やPropTypes
について何も知る必要はありません。
これを行うには、オブジェクトレスト演算子を使用します。 このオペレーターは、分解中に引き出されなかったアイテムを収集し、それらを新しいオブジェクトに保存します。
簡単な例を次に示します。
const dog = { name: 'dog', diet: ['meat'] } const { name, ...props } = dog;
この場合、変数name
は'dog'
になり、変数props
は{ diet: ['meat']}
になります。
これまで、すべての小道具をHTML属性であるかのように渡してきましたが、オブジェクトを使用して小道具を送信することもできます。 オブジェクトを小道具として使用するには、中括弧で囲まれたスプレッド演算子...props
を使用する必要があります。 これにより、各キーと値のペアが小道具に変更されます。
AnimalCard.js
を開きます:
nano src/components/AnimalCard/AnimalCard.js
内部で、分解されたオブジェクトからdiet
を削除し、代わりに残りの小道具をprops
という変数に収集します。 次に、それらの小道具をAnimalDetails
に直接渡します。
ラッパー-tutorial/src / components / AnimalCard / AnimalCard.js
import React from 'react'; import PropTypes from 'prop-types'; import AnimalDetails from '../AnimalDetails/AnimalDetails'; export default function AnimalCard({ name, size, ...props }) { return( <div> <h3>{name}</h3> <div>{size}kg</div> <AnimalDetails {...props} /> </div> ) } AnimalCard.propTypes = { name: PropTypes.string.isRequired, size: PropTypes.number.isRequired, }
このコンポーネントではプロップを使用していないため、diet
PropType
を削除できることに注意してください。
この場合、AnimalDetails
に渡す小道具は1つだけです。 複数の小道具がある場合は、順序が重要になります。 後の小道具は前の小道具を上書きするので、優先したい小道具がある場合は、それが最後であることを確認してください。 props
オブジェクトに名前付きの値でもあるプロパティがある場合、これにより混乱が生じる可能性があります。
ファイルを保存して閉じます。 ブラウザが更新され、すべてが同じように見えます。
...props
オブジェクトがどのように柔軟性を追加するかを確認するために、AnimalCard
コンポーネントを介してscientificName
をAnimalDetails
に渡します。
まず、App.js
を開きます。
nano src/components/App/App.js
次に、scientificName
を小道具として渡します。
ラッパー-tutorial/src / components / App / App.js
import React from 'react'; import './App.css'; import animals from './data'; import AnimalCard from '../AnimalCard/AnimalCard'; function App() { return ( <div className="wrapper"> {animals.map(animal => <AnimalCard diet={animal.diet} key={animal.name} name={animal.name} size={animal.size} scientificName={animal.scientificName} /> )} </div> ); } export default App;
ファイルを保存して閉じます。
AnimalCard
をスキップします。 そこで変更を加える必要はありません。 次に、AnimalDetails
を開いて、新しい小道具を消費できるようにします。
nano src/components/AnimalDetails/AnimalDetails.js
新しい小道具は文字列になり、details
リストにPropType
を宣言する行とともに追加します。
ラッパー-チュートリアル/src/components/AnimalDetails/AnimalDetails.js
import React from 'react'; ... export default function AnimalDetails({ diet, scientificName }) { return( <div className="details"> <h4>Details:</h4> <div> Scientific Name: {scientificName}. </div> <div> Diet: {diet.map(food => convertFood(food)).join(' ')} </div> </div> ) } AnimalDetails.propTypes = { diet: PropTypes.arrayOf(PropTypes.string).isRequired, scientificName: PropTypes.string.isRequired, }
ファイルを保存して閉じます。 これを行うと、ブラウザが更新され、AnimalCard
コンポーネントに変更を加えることなく新しい詳細が表示されます。
このステップでは、未知の小道具を受け取り、spread演算子を使用してネストされたコンポーネントに渡すことができる柔軟な親小道具を作成する方法を学びました。 これは、焦点を絞った責任を持つコンポーネントを作成するために必要な柔軟性を提供する一般的なパターンです。 次のステップでは、組み込みのchildren
プロップを使用して、未知のコンポーネントをプロップとして使用できるコンポーネントを作成します。
ステップ3—children
を使用してラッパーコンポーネントを作成する
このステップでは、未知のコンポーネントのグループを小道具として受け取ることができるラッパーコンポーネントを作成します。 これにより、標準のHTMLのようなコンポーネントをネストできるようになり、再利用可能なラッパーを作成するためのパターンが得られます。これにより、共通のデザインでありながら柔軟なインテリアを必要とするさまざまなコンポーネントを作成できます。
Reactは、子コンポーネントを収集するchildren
と呼ばれる組み込みの小道具を提供します。 これを使用すると、ラッパーコンポーネントの作成が直感的で読みやすくなります。
まず、Card
という新しいコンポーネントを作成します。 これは、新しいカードコンポーネントの標準スタイルを作成するためのラッパーコンポーネントになります。
新しいディレクトリを作成します。
mkdir src/components/Card
次に、テキストエディタでCard
コンポーネントを開きます。
nano src/components/Card/Card.js
次のコードを追加して、children
とtitle
を小道具として受け取り、それらをdiv
でラップするコンポーネントを作成します。
ラッパー-tutorial/src / components / Card / Card.js
import React from 'react'; import PropTypes from 'prop-types'; import './Card.css'; export default function Card({ children, title }) { return( <div className="card"> <div className="card-details"> <h2>{title}</h2> </div> {children} </div> ) } Card.propTypes = { children: PropTypes.oneOfType([ PropTypes.arrayOf(PropTypes.element), PropTypes.element.isRequired ]), title: PropTypes.string.isRequired, }
children
のPropTypes
は新品です。 children
小道具は、JSX要素またはJSX要素の配列のいずれかです。 title
は文字列です。
ファイルを保存して閉じます。
次に、スタイリングを追加します。 Card.css
を開きます:
nano src/components/Card/Card.css
カードの詳細の下に境界線と線が表示されます。
ラッパー-tutorial/src / components / Card / Card.css
.card { border: black solid 1px; margin: 10px; padding: 10px; width: 200px; } .card-details { border-bottom: gray solid 1px; margin-bottom: 20px; }
ファイルを保存して閉じます。 コンポーネントができたので、それを使用する必要があります。 各AnimalCard
をApp.js
のCard
コンポーネントでラップできますが、AnimalCard
という名前は、すでにCard
であることを示しているため、 AnimalCard
内でCard
コンポーネントを使用することをお勧めします。
AnimalCard
を開きます:
nano src/components/AnimalCard/AnimalCard.js
他の小道具とは異なり、children
を明示的に渡すことはありません。 代わりに、HTMLの子要素であるかのようにJSXを含めます。 つまり、次のように、要素内にネストするだけです。
ラッパー-tutorial/src / components / AnimalCard / AnimalCard.js
import React from 'react'; import PropTypes from 'prop-types'; import Card from '../Card/Card'; import AnimalDetails from '../AnimalDetails/AnimalDetails'; export default function AnimalCard({ name, size, ...props }) { return( <Card title="Animal"> <h3>{name}</h3> <div>{size}kg</div> <AnimalDetails {...props} /> </Card> ) } AnimalCard.propTypes = { name: PropTypes.string.isRequired, size: PropTypes.number.isRequired, }
Reactコンポーネントとは異なり、子として単一のルート要素を持つ必要はありません。 そのため、Card
のPropType
は、要素の配列または単一の要素である可能性があると指定しました。 children
をネストされたコンポーネントとして渡すことに加えて、カードにAnimal
というタイトルを付けます。
ファイルを保存して閉じます。 これを行うと、ブラウザが更新され、更新されたカードコンポーネントが表示されます。
これで、ネストされた子をいくつでも使用できる再利用可能なCard
コンポーネントができました。 これの主な利点は、Card
を任意のコンポーネントで再利用できることです。 Plant
カードを作成したい場合は、植物情報をCard
コンポーネントでラップすることで作成できます。 関連付ける必要すらありません。音楽やアカウントデータなどを一覧表示するまったく異なるアプリケーションでCard
コンポーネントを再利用したい場合は、それも可能です。 Card
コンポーネントは、子が何であるかを気にしません。 ラッパー要素を再利用しているだけです。この場合は、スタイル付きの境界線とタイトルです。
children
を使用することの欠点は、子プロップのインスタンスを1つしか持てないことです。 場合によっては、コンポーネントにカスタムJSXを複数の場所に配置する必要があります。 幸い、JSXコンポーネントとReactコンポーネントを小道具として渡すことでこれを行うことができます。これについては、次のステップで説明します。
ステップ4—コンポーネントを小道具として渡す
このステップでは、Card
コンポーネントを変更して、他のコンポーネントを小道具として使用します。 これにより、コンポーネントは、ページ全体の複数の場所に不明なコンポーネントまたはJSXを表示するための最大限の柔軟性が得られます。 一度しか使用できないchildren
とは異なり、小道具と同じ数のコンポーネントを使用できるため、ラッパーコンポーネントは、標準の外観と構造を維持しながら、さまざまなニーズに適応できます。
この手順を完了すると、子コンポーネントをラップしたり、カード内の他のコンポーネントを表示したりできるコンポーネントができあがります。 このパターンは、単純な文字列や整数よりも複雑な情報を必要とするコンポーネントを作成する必要がある場合に柔軟性を提供します。
Card
コンポーネントを変更して、details
という任意のReact要素を取得してみましょう。
まず、Card
コンポーネントを開きます。
nano src/components/Card/Card.js
次に、details
という新しい小道具を追加し、<h2>
要素の下に配置します。
ラッパー-tutorial/src / components / Card / Card.js
import React from 'react'; import PropTypes from 'prop-types'; import './Card.css'; export default function Card({ children, details, title }) { return( <div className="card"> <div className="card-details"> <h2>{title}</h2> {details} </div> {children} </div> ) } Card.propTypes = { children: PropTypes.oneOfType([ PropTypes.arrayOf(PropTypes.element), PropTypes.element.isRequired ]), details: PropTypes.element, title: PropTypes.string.isRequired, } Card.defaultProps = { details: null, }
この小道具はchildren
と同じタイプになりますが、オプションである必要があります。 オプションにするには、デフォルト値null
を追加します。 この場合、ユーザーが詳細を渡さなくても、コンポーネントは引き続き有効であり、余分なものは何も表示されません。
ファイルを保存して閉じます。 ページが更新され、以前と同じ画像が表示されます。
次に、AnimalCard
にいくつかの詳細を追加します。 まず、AnimalCard
を開きます。
nano src/components/AnimalCard/AnimalCard.js
Card
コンポーネントはすでにchildren
を使用しているため、新しいJSXコンポーネントを小道具として渡す必要があります。 これらはすべて哺乳類なので、カードに追加しますが、<em>
タグで囲んで斜体にします。
ラッパー-tutorial/src / components / AnimalCard / AnimalCard.js
import React from 'react'; ... export default function AnimalCard({ name, size, ...props }) { return( <Card title="Animal" details={<em>Mammal</em>}> <h3>{name}</h3> <div>{size}kg</div> <AnimalDetails {...props} /> </Card> ) } ...
ファイルを保存します。 これを行うと、ブラウザが更新され、Mammalというフレーズを含む更新が表示されます。
この小道具は、あらゆるサイズのJSXを使用できるため、すでに強力です。 この例では、要素を1つだけ追加しましたが、必要なだけJSXを渡すことができます。 また、JSXである必要はありません。 たとえば、複雑なマークアップがある場合は、それを小道具に直接渡したくないでしょう。 これは読みにくいでしょう。 代わりに、別のコンポーネントを作成してから、そのコンポーネントを小道具として渡すことができます。
これが機能していることを確認するには、AnimalDetails
をdetails
小道具に渡します。
ラッパー-tutorial/src / components / AnimalCard / AnimalCard.js
import React from 'react'; ... export default function AnimalCard({ name, size, ...props }) { return( <Card title="Animal" details={ <AnimalDetails {...props} /> } > <h3>{name}</h3> <div>{size}kg</div> </Card> ) } ...
AnimalDetails
はより複雑で、マークアップの行がいくつかあります。 details
に直接追加すると、小道具が大幅に増えて読みにくくなります。
ファイルを保存して閉じます。 これを行うと、ブラウザが更新され、カードの上部に詳細が表示されます。
これで、カスタムJSXを取得して複数の場所に配置できるCard
コンポーネントができました。 あなたは単一の小道具に制限されていません。 必要な数の小道具に要素を渡すことができます。 これにより、柔軟なラッピングコンポーネントを作成して、他の開発者が全体的なスタイルと機能を維持しながらコンポーネントをカスタマイズできるようになります。
コンポーネントを小道具として渡すことは完璧ではありません。 読みにくく、children
を渡すほど明確ではありませんが、柔軟性があり、コンポーネントで必要な数だけ使用できます。 最初にchildren
を使用する必要がありますが、それでも不十分な場合は、遠慮なく小道具にフォールバックしてください。
このステップでは、JSXコンポーネントとReactコンポーネントを小道具として別のコンポーネントに渡す方法を学びました。 これにより、ラッパーコンポーネントがJSXまたはコンポーネントを処理するために複数の小道具を必要とする可能性がある多くの状況を処理する柔軟性がコンポーネントに与えられます。
結論
予測可能な外観と構造を維持しながら、データを柔軟に表示できるさまざまなラッピングコンポーネントを作成しました。 未知の小道具を収集してネストされたコンポーネントに渡すことができるコンポーネントを作成しました。 また、組み込みのchildren
プロップを使用して、任意の数のネストされた要素を処理できるラッパーコンポーネントを作成しました。 最後に、JSXまたはReactコンポーネントを小道具として使用できるコンポーネントを作成し、ラッパーコンポーネントがさまざまなカスタマイズの複数のインスタンスを処理できるようにしました。
ラッパーコンポーネントを使用すると、コードの再利用と一貫性を最大化しながら、未知の状況に適応することができます。 このパターンは、ボタン、アラート、モーダル、スライドショーなど、アプリケーション全体で再利用する基本的なUI要素を作成するのに役立ちます。 あなたは何度もそれに戻っていることに気付くでしょう。
Reactのチュートリアルをもっと見たい場合は、 Reactトピックページを確認するか、React.jsシリーズのコーディング方法ページに戻ってください。