React で親コンポーネントの state を下位のコンポーネントのイベント処理で更新する
概要
親コンポーネントで state を管理しているが、input 要素などの子コンポーネント側でイベント処理を行いたい時があると思います。結論から言うと、この場合の解決策の1つとしては、**「親コンポーネントから props 経由でハンドラー関数を渡す」**というやり方があります。気づけばカンタンなことですが、自分はハマってしまったので、誰かの参考になればと思って投稿しました。なお、React 初心者のため、もっと良い解決策がありましたら、ご教授ください。
本題
親コンポーネント Parent
import React, { useState } from 'react';
import Child from './Child.js';
function Parent() {
// hook's state administration
const [inputText, setInputText] = useState("");
// handler function
function handleInputTextChange(text) {
setInputText(text);
}
return (
<div className="App">
<div className="Searcher">
//!important->
<Child handleInputTextChange={e => handleInputTextChange(e)}/>
//<-!imoprtant
</div>
// display 'inputText' contents
<p>{inputText}</p>
</div>
);
}
子コンポーネント Child
import React from 'react';
import Paper from '@material-ui/core/Paper';
import InputBase from '@material-ui/core/InputBase';
import SearchIcon from '@material-ui/icons/Search';
import IconButton from '@material-ui/core/IconButton';
function Child() {
return (
<Paper component="form">
<InputBase
//!important->
onChange={(e) => props.handleInputTextChange(e.target.value)}
//<-!imoprtant
/>
<IconButton type="submit">
<SearchIcon />
</IconButton>
</Paper>
);
}
export default Child;
親コンポーネント Parent
と子コンポーネント Child
を示しました。
今回の例では、Child
にテキスト入力部分 InputeBase
があり、そのテキスト入力の state を inputText
という変数で、Parent
において保持します。テキストの変化は、 handleInputTextChange
というハンドラー関数で制御します。そして、 Parent
で inputText
の内容を表示しています。挙動は以下のようになります。
ポイント
今回の解説のポイントは、**「親コンポーネントからprops経由でハンドラー関数を渡す」**ことです。注意すべき点は以下の2点です。
-
Parent
では、<Child handleInputTextChange={e => handleInputTextChange(e)}/>
のように、Child
において制御する関数をChild
の属性として渡すこと -
Child
ではprops.handleInputTextChange(e.target.value)
のようにParent
から受け取る関数の前にprops
をつけること
です。
どうしてこのようなことが必要になってくるのかというと、React では、制御されたコンポーネントの考えに基づき、親要素で state を管理することが一般的です。そこで state の管理もハンドラー関数も親要素で管理するとなりますが、その制御関数を子要素に渡すことができないとなると、親要素のファイル上で子要素を定義せざるを得なくなり、コードの量が増えてシンプルではありません。そこで、こういうときは props
経由で関数を渡すと良いと思います。もちろん、親子の階層構造がもっと複雑になった場合、state を一箇所で管理する Redux
の導入も考えられるでしょうが、カンタンなものを作るだけであればこれで十分ではないでしょうか?
挙動
コードの解説
-
ユーザーが入力するテキストが変化すると、子コンポーネント
Child
のinputBase
のonChange
が発火します。 -
onChange
に指定された関数props.handleInputTextChange
はParent
からprops
経由で渡されたものですが、Parent
におけるhandleInputTextChange
の定義により、ここでsetInputText
によりstate であるinputText
が更新されます。 -
state が更新されたことを受けて React の DOM ツリーが再描画され、
Parent
の<p>inputText</p>
部分が書き換えられます。
UI
UI上の挙動は以下のようになります。 テキストの入力に合わせて、テキストの下に表示されるp要素の内容が変化します。
以上です。いいねしてね。