はい、そこはかなり大事です。
初心者のうちは特に、
- どのファイルで呼んでいるのか
- どのファイルで受け取っているのか
- 親と子の関係がどこで分かれるのか
が見えないと、急にわかりにくくなります。
なので、「呼び出し側」と「コンポーネント側」をファイル名つきで、もう少し丁寧に書いた版をそのまま Qiita に入れやすい形で作ります。
Reactの props・分割代入・データの受け渡しを初心者向けに整理してみた
React を勉強していると、よく出てくるのがこのあたりです。
props- 分割代入
- 親コンポーネント → 子コンポーネントへの値の受け渡し
- 子コンポーネント → 親コンポーネントへの通知
最初は、
- どっちが親なのか
- どっちが呼び出しているのか
- どのファイルで値を渡しているのか
- どのファイルで受け取っているのか
が混ざってしまいやすいので、ファイル名つきで整理します。
まず結論:親が呼び出し側、子が受け取り側
React では基本的に、
- 親コンポーネント = 呼び出し側
- 子コンポーネント = 受け取り側
です。
たとえばこのような形です。
<Title text="会員登録" />
この1行は、
-
Titleコンポーネントを呼び出している -
textという名前で値を渡している
という意味です。
そして Title コンポーネント側では、その値を props で受け取ります。
例1:文字列を渡す基本形
まずは一番基本の例です。
ファイル構成
src/
├─ App.jsx
└─ components/
└─ Title.jsx
呼び出し側(親)
src/App.jsx
import Title from "./components/Title";
function App() {
return (
<div>
<Title text="会員登録" />
</div>
);
}
export default App;
コンポーネント側(子)
src/components/Title.jsx
function Title(props) {
return <h1>{props.text}</h1>;
}
export default Title;
何が起きているか
App.jsx の中で、
<Title text="会員登録" />
と書いています。
これは、
-
Titleという子コンポーネントを呼び出している -
textという props に"会員登録"を渡している
という意味です。
そして Title.jsx では、
function Title(props) {
return <h1>{props.text}</h1>;
}
と書いているので、親から渡された text を props.text として使えます。
例2:props はオブジェクトで受け取っている
ここが最初のつまずきポイントでした。
呼び出し側でこう書くとします。
src/App.jsx
<Title text="会員登録" color="blue" />
すると子側では、props はこういう形のオブジェクトで渡されているイメージです。
{
text: "会員登録",
color: "blue"
}
なので、子側ではこう書けます。
src/components/Title.jsx
function Title(props) {
return (
<h1 style={{ color: props.color }}>
{props.text}
</h1>
);
}
export default Title;
例3:分割代入を使う書き方
React ではこちらの書き方もよく出てきます。
呼び出し側(親)
src/App.jsx
import Title from "./components/Title";
function App() {
return (
<div>
<Title text="会員登録" color="blue" />
</div>
);
}
export default App;
コンポーネント側(子)
src/components/Title.jsx
function Title({ text, color }) {
return <h1 style={{ color }}>{text}</h1>;
}
export default Title;
何が違うのか
さっきはこうでした。
function Title(props) {
return <h1>{props.text}</h1>;
}
今回はこうです。
function Title({ text, color }) {
return <h1 style={{ color }}>{text}</h1>;
}
これは、props の中から必要な値を最初に取り出しているだけです。
つまり、
function Title({ text, color }) {
は、ほぼこういう意味です。
function Title(props) {
const text = props.text;
const color = props.color;
なので、書き方が省略されているだけで、やっていることは同じです。
例4:children を使う場合
children も、呼び出し側と受け取り側を分けて考えるとわかりやすいです。
ファイル構成
src/
├─ App.jsx
└─ components/
└─ Button.jsx
呼び出し側(親)
src/App.jsx
import Button from "./components/Button";
function App() {
return (
<div>
<Button>送信する</Button>
</div>
);
}
export default App;
コンポーネント側(子)
src/components/Button.jsx
function Button(props) {
return <button>{props.children}</button>;
}
export default Button;
何が起きているか
親側では、
<Button>送信する</Button>
と書いています。
この タグの間に書いたもの が、子側では props.children に入ります。
つまり、子側で受け取るとこう見えます。
function Button(props) {
console.log(props);
return <button>{props.children}</button>;
}
イメージとしては、
{
children: "送信する"
}
のような感じです。
例5:children も分割代入できる
src/components/Button.jsx
function Button({ children }) {
return <button>{children}</button>;
}
export default Button;
これは、
function Button(props) {
return <button>{props.children}</button>;
}
と同じ意味です。
例6:関数を渡す場合
ここが「データの受け渡し」の中でも少し難しいところです。
でも React ではかなりよく使います。
ファイル構成
src/
├─ App.jsx
└─ components/
└─ Button.jsx
呼び出し側(親)
src/App.jsx
import Button from "./components/Button";
function App() {
const handleClick = () => {
alert("送信しました");
};
return (
<div>
<Button onClick={handleClick}>送信</Button>
</div>
);
}
export default App;
コンポーネント側(子)
src/components/Button.jsx
function Button({ children, onClick }) {
return <button onClick={onClick}>{children}</button>;
}
export default Button;
何が起きているか
親側では、
<Button onClick={handleClick}>送信</Button>
としています。
これは、
-
childrenに"送信" -
onClickにhandleClickという関数
を渡しているということです。
子側ではその関数を受け取って、
<button onClick={onClick}>{children}</button>
としているので、ボタンが押されたときに親側の handleClick が実行されます。
例7:子から親へ値を渡すように見えるパターン
React でよく「子から親へデータを渡す」と言いますが、実際には
親が渡した関数を子が実行している
という形です。
ファイル構成
src/
├─ App.jsx
└─ components/
└─ FruitButton.jsx
呼び出し側(親)
src/App.jsx
import FruitButton from "./components/FruitButton";
function App() {
const handleSelect = (fruit) => {
console.log("選ばれた果物:", fruit);
};
return (
<div>
<FruitButton onSelect={handleSelect} />
</div>
);
}
export default App;
コンポーネント側(子)
src/components/FruitButton.jsx
function FruitButton({ onSelect }) {
return (
<button onClick={() => onSelect("りんご")}>
りんごを選ぶ
</button>
);
}
export default FruitButton;
流れを整理すると
親側でやっていること
App.jsx で
const handleSelect = (fruit) => {
console.log("選ばれた果物:", fruit);
};
という関数を作っています。
その関数を、
<FruitButton onSelect={handleSelect} />
で子に渡しています。
子側でやっていること
FruitButton.jsx では
function FruitButton({ onSelect }) {
で関数を受け取っています。
そしてボタンを押したときに、
() => onSelect("りんご")
を実行しています。
つまり子が勝手に親へ送っているのではなく、
親からもらった関数に "りんご" を渡して実行している
ということです。
例8:オブジェクトを渡す場合
ファイル構成
src/
├─ App.jsx
└─ components/
└─ Profile.jsx
呼び出し側(親)
src/App.jsx
import Profile from "./components/Profile";
function App() {
const user = {
name: "田中",
age: 28,
job: "エンジニア",
};
return (
<div>
<Profile user={user} />
</div>
);
}
export default App;
コンポーネント側(子)
src/components/Profile.jsx
function Profile(props) {
return (
<div>
<p>名前: {props.user.name}</p>
<p>年齢: {props.user.age}</p>
<p>職業: {props.user.job}</p>
</div>
);
}
export default Profile;
分割代入するならこう
src/components/Profile.jsx
function Profile({ user }) {
return (
<div>
<p>名前: {user.name}</p>
<p>年齢: {user.age}</p>
<p>職業: {user.job}</p>
</div>
);
}
export default Profile;
さらに中身も取り出すなら、
function Profile({ user }) {
const { name, age, job } = user;
return (
<div>
<p>名前: {name}</p>
<p>年齢: {age}</p>
<p>職業: {job}</p>
</div>
);
}
です。
ただ、初心者のうちは無理に短くしすぎず、
まずは user.name のように追える書き方でも十分だと思います。
呼び出し側とコンポーネント側を読むコツ
自分は次の順番で見ると整理しやすかったです。
1. まず呼び出し側を見る
たとえばこれです。
<Button onClick={handleClick}>送信</Button>
ここを見ると、
-
Buttonコンポーネントを使っている -
onClickを渡している - タグの中に
送信と書いてある
とわかります。
2. 次にコンポーネント側を見る
function Button({ children, onClick }) {
return <button onClick={onClick}>{children}</button>;
}
ここを見ると、
-
childrenを表示に使っている -
onClickを button に付けている
とわかります。
3. 「親が何を渡し、子が何を受け取るか」を対応させる
この対応です。
<Button onClick={handleClick}>送信</Button>function Button({ children, onClick })
つまり、
-
onClick={handleClick}→onClick -
送信→children
です。
これがわかると、一気に読みやすくなります。
初心者向けにおすすめの書き方
最初のうちは、いきなり複雑にしないほうがわかりやすいです。
まずは props で受ける
function Card(props) {
return <div>{props.title}</div>;
}
慣れたら分割代入
function Card({ title }) {
return <div>{title}</div>;
}
children は「タグの中身」と覚える
<Card>お知らせ</Card>
↓
function Card({ children }) {
return <div>{children}</div>;
}
まとめ
React のデータ受け渡しは、ファイルごとに見るとかなり整理しやすいです。
-
App.jsxなどの親コンポーネントが呼び出し側 -
components/Button.jsxなどが受け取り側 - 親が props を渡す
- 子が props で受け取る
- タグの中身は
children - 関数も props で渡せる
特に初心者のうちは、
「この値はどのファイルで渡して、どのファイルで受け取っているのか」
を意識すると理解しやすいと思います。
おまけ:最小サンプル一式
src/App.jsx
import Title from "./components/Title";
import Button from "./components/Button";
function App() {
const handleClick = () => {
alert("送信しました");
};
return (
<div>
<Title text="会員登録" />
<Button onClick={handleClick}>送信</Button>
</div>
);
}
export default App;
src/components/Title.jsx
function Title({ text }) {
return <h1>{text}</h1>;
}
export default Title;
src/components/Button.jsx
function Button({ children, onClick }) {
return <button onClick={onClick}>{children}</button>;
}
export default Button;