【持っておいてほしい前提知識】
- reactにおいて親コンポーネント、子コンポーネントの概念、使い方を雰囲気でも理解していること
-
例えば以下が何となくわかる
- 親コンポーネント内に別ファイルからexportされたコンポーネントを子コンポーネントとして利用できる
- コンポーネントのexport、importの仕方がわかる
-
useStateの利用法
-
【注意】
本記事では一部コード内にtypsScriptを利用していますが、typescriptの事前知識や学習は必要ございません。
またnode環境があることを前提としています。
nodeが入っていない方は以下よりインストールをしていただければと思います。
【本記事のスタンス】
- 一旦初学者が理解することを目的に、propsの利用法や概念を簡単な範囲で最低限の説明にとどめています
- 厳密な表現はしておらず、曖昧な表記もありますがご指摘がある場合はコメントいただけると幸いです
【propsの目的】
親コンポーネントから子コンポーネントにデータを渡すためです。
まずはこれだけ覚えましょう。
このことを念頭に置いて、実際にコードを書いてpropsを理解していきましょう
【reactを使ったアプリケーション作成のための環境構築】
適当なディレクトリで以下を実行してください、
npm create vite@latest practice-props-react
何かしらのインタラクションを求められるかと思いますが
基本的には言語仕様を選択する系の質問を求められます。
①reactを選択
②react + typescriptを選択
としてください
続いて以下のコマンドを実行してください(各行逐一実行せずに全部コピペで大丈夫です)
cd practice-props-react
npm i
npm run dev
これでローカルホストでviteが用意してくれているreact実行環境が整ったアプリケーションが立ち上がります。
npm run dev後にポート番号が記された内容がコマンドに出ているかと思いますので、それをブラウザで開きましょう。
【作るものの確認】
各ボタンを押すと各ボタンにセットされた値が増えるだけの簡単なコンポーネントですね。
感の良い人はお気づきかもしれませんが、npm create vite@latestで立ち上がったアプリケーションに似たようなコンポーネントがすでにありますよね。
今回の説明で不要な部分を削除し複製しただけのコンポーネントになります。
propsを使わない場合の実装
すでにあるbuttonのコードを複数するだけですね。
それぞれのボタンの状態は別にしたいので、しっかりとそれぞれのボタンに対して変数をusestateを利用して用意するように注意してください。
import { useState } from 'react'
import './App.css'
function App() {
const [count1, setCount1] = useState<number>(0)
const [count2, setCount2] = useState<number>(0)
const [count3, setCount3] = useState<number>(0)
const [count4, setCount4] = useState<number>(0)
const [count5, setCount5] = useState<number>(0)
return (
<>
<div className="card">
<button onClick={() => setCount1((prev) => prev + 1)}>
<p>count1 is {count1}</p>
</button>
</div>
<div className="card">
<button onClick={() => setCount2((prev) => prev + 1)}>
<p>count2 is {count2}</p>
</button>
</div>
<div className="card">
<button onClick={() => setCount3((prev) => prev + 1)}>
<p>count3 is {count3}</p>
</button>
</div>
<div className="card">
<button onClick={() => setCount4((prev) => prev + 1)}>
<p>count4 is {count4}</p>
</button>
</div>
<div className="card">
<button onClick={() => setCount5((prev) => prev + 1)}>
<p>count5 is {count5}</p>
</button>
</div>
</>
)
}
export default App
propsを使った場合の実装
import { useState } from 'react'
import './App.css'
import Count1 from './component/Count1'
import Count2 from './component/Count2'
import Count3 from './component/Count3'
import Count4 from './component/Count4'
import Count5 from './component/Count5'
function App() {
const [count1, setCount1] = useState<number>(0)
const [count2, setCount2] = useState<number>(0)
const [count3, setCount3] = useState<number>(0)
const [count4, setCount4] = useState<number>(0)
const [count5, setCount5] = useState<number>(0)
return (
<>
<div className="card">
<button onClick={() => setCount1((prev) => prev + 1)}>
<Count1 value={count1} />
</button>
</div>
<div className="card">
<button onClick={() => setCount2((prev) => prev + 1)}>
<Count2 value={count2} />
</button>
</div>
<div className="card">
<button onClick={() => setCount3((prev) => prev + 1)}>
<Count3 value={count3} />
</button>
</div>
<div className="card">
<button onClick={() => setCount4((prev) => prev + 1)}>
<Count4 value={count4} />
</button>
</div>
<div className="card">
<button onClick={() => setCount5((prev) => prev + 1)}>
<Count5 value={count5} />
</button>
</div>
</>
)
}
export default App
そしてsrc/components
フォルダを作成し、その中に以下の様な構成で書くファイルを作成してください。
それぞれの中身:
interface props {
value: number
}
const Count1 = (props: props) => {
return (
<p>count1 is {props.value}</p>
)
}
export default Count1
interface props {
value: number
}
const Count2 = (props: props) => {
return (
<p>count2 is {props.value}</p>
)
}
export default Count2
interface props {
value: number
}
const Count3 = (props: props) => {
return (
<p>count3 is {props.value}</p>
)
}
export default Count3
interface props {
value: number
}
const Count4 = (props: props) => {
return (
<p>count4 is {props.value}</p>
)
}
export default Count4
interface props {
value: number
}
const Count5 = (props: props) => {
return (
<p>count5 is {props.value}</p>
)
}
export default Count5
【何が変わったか?】
各pタグ部分が
<p>count1 is {count1}</p>
から
<Count1 value={count1} />
となり子コンポーネント化されています。
【※最重要事項 propsを利用したデータの渡し方・渡され方】
渡し方
<Count1 value={count1} />
<子コンポーネント key={value} /> の形で、keyとvalueをセットします。
- keyの名前は事前で設定して良いです
- valueも自分で設定して良いですし、今回のように変数を渡すこともできます
JSX/TSXで変数を書く際は{}でくくります(JavaScriptと同様)。
渡され方
Count1コンポーネントを見てみましょう:
interface props {
value: number
}
const Count1 = (props: props) => {
return (
<p>count1 is {props.value}</p>
)
}
export default Count1
関数の引数 (props: props)
で親コンポーネントからデータを受け取っています。
重要なのは:
-
props
はオブジェクトであること - 親が定義した
key
→ propsオブジェクトのキー - 親が渡した
value
→ propsオブジェクトのバリュー
つまり:
props = { value: {count1} }
子コンポーネントでその値を使いたい場合:
<p>count1 is {props.value}</p>
【まとめ】
個人的には:
-
目的 → コンポーネント間でのデータのやり取りを可能にする
-
利用法
- 親から子へのpropsの渡し方
- 子でのpropsの受け取り方
特に"受け取り方がオブジェクトである"という理解があれば、あとはJavaScriptの知識で対応可能です。
少しでもpropsの理解が深まれば幸いです。何かご不明点があればぜひコメントください。