deve.K

エンジニアが未来を切り開く。

Reactのprops(小道具)をすべて理解する 渡し方

Reactでのpropsの渡し方

本日はReactでProps(小道具)を扱う際に知っておくべきことすべてを初学者様に解説致します。

関数コンポーネントでは、クラスコンポーネントとは違って小道具の取り扱いは非常に簡単です。

ReactのProps(小道具)とは?

コンポーネントを再利用すると、両方の時間で同じコンテンツが表示され続けます。

ですが、他のテキストや外部ソースからデータをフェッチしている間、事前に情報が分からない場合は非常に厄介です。

HTML要素では、要素の動作を変更したりする情報を渡すために使用される属性があるのはご存知かも知れません。

例えば『 src 』『 < a > 』『 < img > 』などなどです。

これらは表示された画像やタグの属性を変更すると、リンク先が変更され、レンダリングされます。

これと同様に、情報をReactコンポーネントに渡す事ができるのがあります。

それをProps(小道具)と呼んでいます。

Propsはプロパティです。

つまり、それら情報をプロパティとしてReactのコンポーネントに渡しています。

このPropsを、親コンポーネントから子のコンポーネントに渡します。

JavaScript関数の引数やHTMLの属性に非常に似ています。

Propsは、HTML属性を介してコンポーネントに渡されていきます。

そして、データはコンポーネントツリーを下に流れていきます、バケツリレー式で渡されたコンポーネントとも言ったりします。

これは、一方向のデータフローと呼ばれており基本的には一方通行となっています。

Propsはデータの読み取り専用となっています

つまりコンポーネント内のPropsは不変であるため、他のコンポーネントへ渡された値を変更する事はできません。

値を変更するとエラーが返されます。

変更する際は、渡された子コンポーネントではなく親のコンポーネントで変更するしかありません。

なぜなのかは、Propsでは親コンポーネントで常にデータを保持されているからです。

Propsを使用しデータを表示したり、そのデータを使用してコンポーネントインタラクティブに設計することが可能であり、さまざまな状況に適応できるコンポーネントを作成するための重要な部分となっております。

抑えておくべきPropsルール

Propsは親コンポーネントから子コンポーネントのリレー式で渡される、一方向のデータフロー。

Propsは読み取り専用のプロパティ

Propsは不変です、一度設定するとPropsの値は変更できません、Propsの値の変更は親コンポーネントで行う。

Propsは、関数コンポーネントとクラスコンポーネントの両方で使用可能です。

関数コンポーネントでPropsを渡す方法

コンポーネントのApp関数コンポーネントに『greeting』変数として宣言します。

当記事では、このAppコンポーネントを最上位(親)コンポーネントとします。

const App = () => {
  
const greeting = 'Welcome to the world of React.js!';

  return (
    <div>
    <Child />
    </div>
  );
}  

子のコンポーネントを作成しましょう、Childコンポーネントとします。

const Child = () => {

return (
<div>

</div>);
};

Reactコンポーネントから別のコンポーネントにデータを渡す方法は、コンポーネントレンダリングするときは、属性のような構文を使用してPropsをコンポーネントに追加します。

任意のProps名を自由に使用可能です。

下記でしたら『text』となります。

const App = () => {
  
const greeting = 'Welcome to the world of React.js!';

  return (
    <div>
    <Child text={greeting} />
    </div>
  );
}

変数としてPropsを渡します。

子のコンポーネント関数の最初の引数として常にPropsを受けとります。

const Child = (props) => {

return (
<div>

<h2>{props.text}</h2>

</div>);
};

See the Pen Untitled by dev.K | Webアプリ開発者 (@enjinia_f) on CodePen.


もし、コンポーネントレンダリング時にPropsが指定されていない場合は、デフォルトのPropsが使用されます。

const Child = (props) => {

つまり、必要なデータが子コンポーネントに渡されますが、子コンポーネントがデータを受信しないことがあります。

その場合では子コンポーネントがデータを受け取らなくても、いくつかの値を表示するようにデフォルトの Propsを設定する必要があるのです。

デフォルトPropsがない場合、Propsを受け取らないがJSXにProps値を表示する子コンポーネントには何も表示されません。

ですが、Propsを渡されているがレンダリング時に何も表示しないのはベストプラクティスではありません。

Reactアプリケーションが誤作動していると考えてしまいます。

コンポーネントからコンポーネントに渡されるすべてのデータを保持するJavaScriptオブジェクトであるため、Propsを分解する事が可能です。

引数に波括弧で囲います。

上記と同様の出力となります。

const Child = ({ text }) => {

return (
<div>

<h2>{text}</h2>

</div>);
};

Propsの分解は、オブジェクトで複数のPropsを子コンポーネントに渡す際に使用します。

const Child = ({ text, bool, num }) => {

Propsの分解は後程、詳しく解説致します。

ご覧の通り、Propsを使用すると、あるコンポーネントからコンポーネントツリーの別のコンポーネントに値を渡すことができます。

See the Pen React props by dev.K | Webアプリ開発者 (@enjinia_f) on CodePen.


変数宣言をせずに値を直接、子コンポーネントに渡したい場合は、Propsをインラインで定義すると可能となります。

波括弧内{ }にクォートで定義します。

JavaScript文字列では、一重引用符または二重引用符内にPropsとして渡すことができるという事です。

const App = () => {
  
  return (
    <div>
    <Child greet={"Hello, Taro."} />
    </div>
  );
}

const Child = ({ greet }) => {

return (
<div>

<h2>{greet}</h2>

</div>);
};

Reactでは、 Propsが持つことができる値に制限はありません。

ただし、二重引用符で囲まれた文字列リテラルを除くすべての値は、波括弧で囲む必要があります。

See the Pen React props inline by dev.K | Webアプリ開発者 (@enjinia_f) on CodePen.

コンポーネントで変数として割り当て使用したい場合は、デフォルトのpropsを引数として受けとってから、変数を宣言し割り当てます。

const Child = (props)=> {

const greet = props.greet;

return (
<div>

<h2>{greet}</h2>

</div>);
};

複数のProps

Propsは好きなだけ扱う事も可能です。

const App = () => {
  
  return (
    <div>
    <Child greet={"Hello"} name={"Taro"} />
    </div>
  );
}

const Child = ({ greet, name }) => {

return (
<div>

<h2>{greet}, {name}</h2>

</div>);
};

Childコンポーネントに2つのPropsを受け入れさせて、挨拶メッセージと名前を表示させます。

ここまででは、Propsの値は文字列のみでした。

ただし、Propsを数値、ブール値、オブジェクト、配列、さらにはテンプレートリテラルなどの値に設定したい場合がよくあります。

Propsは、下記のようなあらゆる種類のデータを渡すために使用できます。

String

Array

Integer(整数)

Boolean

Object

Function

それらを見ていきましょう。

変数を含むテンプレートリテラル

ES6の便利な機能である、テンプレートリテラルで変数を含むリテラル表記でPropsを子コンポーネントに渡します。

const App = () => {

  const myName = "Taro";

  return (
    <div>
    <Child name={`My name is ${myName}`} />
    </div>
  );
}

const Child = ({ name }) => {

return (
<div>

<h2>{name}</h2>

</div>);
};

See the Pen 小道具の変数を含むテンプレートリテラル by dev.K | Webアプリ開発者 (@enjinia_f) on CodePen.


テンプレートリテラルの場合、複数行の文字列ははるかにクリーンとなります。

Reactで再利用可能なコンポーネントを操作するときに特に役立ちます。

数値

ReactのコンポーネントにPropsとして数値を渡すには、数値を波括弧で囲みます。

const App = () => {
  return (
    <div>
    <Child num={40} />
    </div>
  );
}

const Child = ({ num }) => {

return (
<div>

<h2>Number: {num}</h2>

</div>);
};

See the Pen 数値リテラルで小道具を渡す by dev.K | Webアプリ開発者 (@enjinia_f) on CodePen.


コンポーネントに『num』というPropsを渡しています。

必ず、波括弧で囲む必要があることに注意して下さい。

もちろん、数値でも複数の小道具を分解して使用する事も可能となります。

ブール値

ブール値でも同様に波括弧を使用してあげます。

boolというProps名にはtrueとして渡します。

const App = () => {
  return (
    <div>
    <Child bool={true} />
    </div>
  );
}

const Child = ({ bool }) => {

return (
<div>

<h2> {bool && <h1>Hello!!</h1>}</h2>

</div>);
};

See the Pen ブール値を小道具として渡す by dev.K | Webアプリ開発者 (@enjinia_f) on CodePen.


コンポーネントでPropsを受けとり、論理演算子である&&を使用し『Hello!!』を表示させます。

Propsの値をfalseとして渡せば、『Hello!!』は表示されません。

注意点は、Propsとして渡す際に『"false"』などのように文字列としてブール値を囲まないようにして下さい。

それはfalseではなく文字列です。

ブール値をPropsとして渡す際は、明示的に指定してあげる必要があります。

配列リテラル

const App = () => {
  const arr = ["Apple, ", "Banana, ", "Lemon"];
  return (
    <div>
    <Child array={arr} />
    </div>
  );
}

const Child = ({ array }) => {

return (
<div>

<h2> {array}</h2>

</div>);
};

基本的には、子コンポーネントは配列に対してmap()構文などを使用して、配列の要素をレンダリングさせます。

const Child = ({ array }) => {

return (
<div>

<h2> 
   {array.map((arr, i) => (
     <ul>
         <li key={i}>{arr}</li>
     </ul>
      ))}
  </h2>

</div>);

See the Pen 配列リテラルとして小道具を渡す by dev.K | Webアプリ開発者 (@enjinia_f) on CodePen.


下記でも同様に機能します。

onst Child = ({ array }) => {

return (
<div>

<h2> 
   {array.map(index => {
        return <div key={index}>{index}</div>;
      })}
  </h2>

</div>);
};

配列をPropsで渡す際、インラインとして渡す事も可能です。

const App = () => {

  return (
    <div>
<Child array={["Apple, ", "Banana, ", "Lemon"]} />
    </div>
  );
}

配列をループ処理する場合は、keyの各要素に一意のPropsを設定するようにしてください。

それは、Reactが要素を互いに区別し、仮想DOMと実際のDOMを区別する際のパフォーマンスを向上させ、配列要素を更新するだけでアプリケーションを高速化できるためとなります。

配列要素をPropsとして渡す際に、個別で渡したい場合もあるかと思います。

上記の配列で、AppleとBananaだけをそれぞれ個別に子コンポーネントにPropsとして渡します。

const App = () => {
  const arr = ["Apple", "Banana", "Lemon"]
  return (
    <div>
    <Child a={arr[0]} b={arr[1]} />
    </div>
  );
}

const Child = ({ a, b }) => {
return (
<div>
<h2> 
   {a},  {b}
  </h2>
</div>);
};

See the Pen 配列要素を個別で小道具として渡す by dev.K | Webアプリ開発者 (@enjinia_f) on CodePen.


特定のインデックスにある配列要素にアクセスすることで、個々の配列要素をPropsとしてコンポーネントに渡すことが可能となります。

配列要素のインデックス番号を忘れないようにして下さい。

オブジェクトをPropsとして渡す

コンポーネントのPropsを動的に作成する場合は、コンポーネントのPropsを純粋なJavaScriptオブジェクト内に保持することができます。

スプレッド構文(...)を使用し、オブジェクトをPropsとしてReactの子コンポーネントに渡します。

Spread構文は、オブジェクトのすべてのプロパティを解凍し、それらをPropsとして指定されたコンポーネントに渡します。

反復可能なオブジェクトまたは配列を文字列を含む任意の値をコピー・結合させます。

つまりオブジェクトのプロパティを結合させて複数のプロパティをコピーし、それをPropsとして子コンポーネントに動的プロパティとして渡します。

const App = () => {
  const obj = {name: "Taro", age: 30, country: " Japan"}
  return (
    <div>
    <Child {...obj} />
    </div>
  );
}

const Child = ({ name, age, country }) => {
return (
<div>

<h2>{name}</h2>
  
<h2>{age}</h2>
  
<h2>{country}</h2>

</div>);
};

See the Pen オブジェクトとして小道具を渡す by dev.K | Webアプリ開発者 (@enjinia_f) on CodePen.


スプレッド構文(...)を使用して 、オブジェクトのプロパティをPropsとして子コンポーネント(Child)に渡しています。

コンポーネントである、Childは引数で渡されたPropsを分解して使用できます。

分解せずに、オブジェクト全体をそのままPropsとして渡したい場合は、オブジェクトのプロパティにアクセスします。

const App = () => {
  const obj = {name: "Taro", age: 30, country: " Japan"}
  return (
    <div>
    <Child data={obj} />
    </div>
  );
}

dataというProps名を用意し、それを子コンポーネントへ渡します。

const Child = ({ data }) => {
return (
<div>

<h2>{data.name}</h2>
  
<h2>{data.age}</h2>
  
<h2>{data.country}</h2>

</div>);
};

これで分解する事なく、オブジェクト全体のデータを受けとりそれぞれ個別に表示します。

オブジェクトをPropsとして渡す際の注意点があります。

オブジェクトが変数に格納されておらず、かつインラインとして渡される場合に限り、オブジェクトをPropsとして渡すときに2つの波括弧{ { } }が必要となります。

//親コンポーネント

 <Child data={ { name: "Taro", age: 30, country: " Japan"} } />

インラインとしてオブジェクトをPropsとして渡す際はこの波括弧{ { } }に気を付けて下さい。

関数をPropsとして渡す

useStateフックを使用してよくあるカウントアップ関数を、Propsとして子コンポーネントへ渡します。

プロパティ名は分かりやすくhandleClickで同じ名前にします。

const App = () => {
  const [count, setCount] = React.useState(0);
  
  function handleClick() {
    setCount(count + 1);
  }
  
  return (
    <div>
       <h2>Count: {count}</h2>
    <Child  handleClick={handleClick} />
    </div>
  );
}

下記の、子コンポーネントで引数に『handleClick』Propsを受けとります。

ボタンタグに埋め込んで、子コンポーネントの関数を使用し機能させます。

const Child = ({ handleClick }) => {

return (
<div>
<button onClick={handleClick}>Increment</button>


</div>);
};

See the Pen 関数を小道具として渡す by dev.K | Webアプリ開発者 (@enjinia_f) on CodePen.


関数をPropsとして渡す際に、関数を呼び出さなかったことに注意してください。

前半で言った通り、Propsは読み取り専用です。

関数を呼び出した結果ではなく、関数への参照を渡すことが非常に重要となっております。

コンポーネントから親にデータを渡す

基本的にはPropsは一方向でのデータ渡しとなっていますが、子コンポーネントから親にデータを渡したい場合があります。

例えば、要素から値を格納する場合は、それらの値を子のコンポーネントから親に取得する必要があります。

コンポーネントでPropsを使用して、コールバック関数を子に渡すことができます。

つまり、親コンポーネントで関数(通常はイベントハンドラ)を定義し、それをコールバック関数として渡すことが可能です。

親から子に関数を渡してあげます。

その関数は何かを返すことができ、親コンポーネントでそれを取得します。

ではオブジェクトの情報を親コンポーネントに渡しましょう。

useStateフックの初期値としてオブジェクトを格納します、プロパティの値は初期値段階では不明とします。

const App = () => {

const [childData, setChildData] = useState({
    name: '不明',
    age: '不明'
  });

  const sendData = (data) => {
    setChildData(data);
  };

  return (
    <div>
      <Child sendData={sendData} />

      <p>ユーザー情報: 名前: {childData.name}, 年齢: {childData.age}
        
      </p>
    </div>
  );
}

コンポーネントであるChildに、オブジェクトのデータを用意します。 

引数にPropsであるsendDataを受け入れます。

イベントハンドラで、useStateフックの初期値が更新されると、子コンポーネントで再定義されたオブジェクトを表示させます。

const Child = ({sendData}) => {
const obj = {
        name: 'Taro',
        age: 30
    };
const ClickHandler = () => {
        sendData(obj);
    }
    
return (
<div>
  <button onClick={ClickHandler}>Click me</button>
</div>);
};

See the Pen 子から親にデータを渡す by dev.K | Webアプリ開発者 (@enjinia_f) on CodePen.


つまり、Propsとして子コンポーネントに関数を渡し、コールバックで親コンポーネントに情報を渡している事になります。

コンポーネントの状態を実行および更新します。

これはもっとも簡単な子から親コンポーネントに情報を渡す方法となります。

プロップドリル(Prop Drilling)

まず、Propsの概念について最初に知っていることを要約してみましょう。

Propsは、トップレベル(最上位)のコンポーネントからWebサイト上の任意の数を子コンポーネントに渡す(またはアクセスできる)データとなります。

Reactを使用する場合、さまざまなコンポーネントとデータを共有する必要が常にあります。

これは、プロップドリルを使用した最も基本的な方法で実現可能です。

つまり、プロップドリルによりコンポーネント間で一方向のデータ共有が可能になります。

プロップドリルは、いくつかのネストされた子コンポーネントを介してデータを渡すための非公式な用語です。

あなたはReactコンポーネントがどのように機能するかを理解する必要があります。

プロップドリル

上記の画像では、AコンポーネントのデータをCコンポーネントでアクセスするには、データをPropsとしてBコンポーネントに渡してから、最後にCコンポーネントに渡す必要があります。

この流れは、スレッディングとして知られております。

つまりプロップドリルとは、親とpropsを使用することになっているコンポーネントの間に多数のコンポーネントがある場合です。

ですが、欠点もございます。

兄弟間でデータを共有したい場合は、初心者からすると少し難しい場合があったりします。

プロップドリルによってコードが複雑になる可能性があります。

コードベースが増えると、Propsの名前が途中で変更された際に、Propsの名前を追跡することが難しくなる可能性があります。

このような状況に遭遇した場合、解決が困難になる事があります。

複雑なコードベースではありませんが、コンポーネントツリーの途中でProps名が変更される例を下記に示します。

See the Pen プロップドリルの流れ by dev.K | Webアプリ開発者 (@enjinia_f) on CodePen.


コンポーネント間でPropsを渡すときは、Propsの名前を変更しないでください。

ではどうすれば良いのか?問題を解決する簡単な方法はいくつかございます。

グローバルストアで必要になる可能性のあるすべての子コンポーネントの状態を維持し、そのストアからデータを取得する状態管理用ライブラリである『Redux』を使用する方法。

もう1つは最近、多くの開発者がReduxではなくReactのContext APIを選択しています。

Context APIは下記で解説しております。

dev-k.hatenablog.com

これらは、ニーズに合ったものを試して使用することができます。

アプリケーションで使用できるプロップドリルの代替手段は他にもあります。

プロップドリルは欠点はありますが、コンポーネント間のデータ転送の実行可能な方法でもあります。

比較的に小さなアプリケーションに使用する必要があります。

ですが、大規模なアプリケーションで作業している場合のデータ転送の主要な方法としてはお勧めできません。

なるべく、アプリケーションを不必要にコンポーネント化しないようにして下さい。

最後に

Propsは、Reactを学習する上で非常に重要な概念です。

コンポーネントから別のコンポーネントにPropsを介して属性を渡すことにより、コンポーネント内で動的データを使用できます。

Propsは読み取り専用コンポーネントであるため、親コンポーネントから渡すPropsは、データが渡された子コンポーネントで変更することはできません。

そして、Propsのデータが変更されるとコンポーネントが再レンダリングされます

Propsは、UIロジックの再利用可能な部分を作成する方法となります。

JestユニットテストでReactコンポーネントのPropsが子に渡されることを確認し、親コンポーネントロジックの単体テストを行い、子コンポーネントに正しいPropsが渡されることを確認する方法がありますので、そちらを強くお勧め致します。

本日は以上となります。

最後までこの記事を読んで頂きありがとうございます。

プライバシーポリシー