はじめに
タイトル通りReactで子コンポーネントから親コンポーネントを操作する方法についてまとめました.
既存記事はありますが,教材用として車輪を再発明します.
やりたいこと
Reactでは親コンポーネントから子コンポーネントに対して値を渡すことは容易です.また,適切にUseStateを使えば,親コンポーネントで値を更新した時コンポーネントの値も自動で更新されます.
しかし,同様の手順では子コンポーネント内の値更新を親コンポーネントに反映させることはできません.
この記事では,この動作の実現を目標とします.

コンポーネントの用意
ここではAppコンポーネントからSubComponentコンポーネントを呼び出す状況を想定します.つまりAppで管理する値をSubComponentコンポーネントから変更することが目標です.
環境はnpm create viteで作成しました.
Appコンポーネント
とりあえずAppコンポーネントに書かれているコードはほぼ消して,Appコンポーネントで管理する値を用意します.
import { useState } from "react";
import "./App.css";
function App() {
const [appValue, setAppValue] = useState(0);
return (
<>
<p>appValue = {appValue}</p>
</>
);
}
export default App;
SubComponentコンポーネント
SubComponentコンポーネントでもそこで管理する値を用意します.また,その値を変えるためのボタンも配置します.
import { useState } from "react";
import "./App.css";
function SubComponent() {
const [subValue, setSubValue] = useState(0);
return (
<>
<p>subValue = {subValue}</p>
<button onClick={() => setSubValue(0)}>subValue = 0</button>
<button onClick={() => setSubValue(1)}>subValue = 1</button>
<button onClick={() => setSubValue(2)}>subValue = 2</button>
</>
);
}
export default SubComponent;
SubComponentからAppコンポーネントの値を変更する
AppコンポーネントでSubComponentを呼び出す
1行加えるだけでOKです.
import { useState } from "react";
import "./App.css";
function App() {
const [appValue, setAppValue] = useState(0);
return (
<>
<p>appValue = {appValue}</p>
+ <SubComponent />
</>
);
}
export default App;
コールバック関数の定義
SubComponentからAppコンポーネントの値を変更するために,AppコンポーネントのsetState(今回はsetAppValue)を受け取れるようにします.このときsetAppValueを引数として受け取ります.ある関数Aに引数として渡される関数Bのことをコールバック関数といいます.
コールバック関数の型はinterfaceで定義し,setAppValueはsetValueという名前で受け取ることにしました.
import { useState } from "react";
import "./App.css";
+interface SubComponentProps {
+ setValue: (value: number) => void;
+}
+ function SubComponent({ setValue }: SubComponentProps) {
const [subValue, setSubValue] = useState(0);
return (
<>
<p>subValue = {subValue}</p>
<button onClick={() => setSubValue(0)}>subValue = 0</button>
<button onClick={() => setSubValue(1)}>subValue = 1</button>
<button onClick={() => setSubValue(2)}>subValue = 2</button>
</>
);
}
export default SubComponent;
コールバック関数の使用
受け取ったsetValueを使うために,buttonで呼び出していた関数を変更します.
import { useState } from "react";
import "./App.css";
interface SubComponentProps {
setValue: (value: number) => void;
}
function SubComponent({ setValue }: SubComponentProps) {
const [subValue, setSubValue] = useState(0);
return (
<>
<p>subValue = {subValue}</p>
+ <button onClick={() => setSubValue(0)}>setValue = 0</button>
+ <button onClick={() => setSubValue(1)}>setValue = 1</button>
+ <button onClick={() => setSubValue(2)}>setValue = 2</button>
</>
);
}
export default SubComponent;
これでSubComponentコンポーネントからの準備は終わりました.
次に,AppコンポーネントからSubComponentコンポーネントにsetValueを渡せるようにします.
import { useState } from "react";
import "./App.css";
import SubComponent from "./SubComponent";
function App() {
const [appValue, setAppValue] = useState(0);
return (
<>
<p>appValue = {appValue}</p>
+ <SubComponent setValue={setAppValue} />
</>
);
}
export default App;
これで下図のようにSubComponentのボタン操作でAppコンポーネントの値を変更できるようになりました.

値の受取
準備段階ではSubComponent上での値が変更できることを確認するために,useStateのsubValueとsetSubValueを定義していました.しかし,上でボタンのonClickにコールバック関数として渡していたsetSubValueはsetValueに置き換えました.つまりsetSubValueは不要です.SubComponentコンポーネントでAppコンポーネントと独立した値を管理する必要も無いので,subValueと合わせて削除してしまいます.
-import { useState } from "react";
import "./App.css";
interface SubComponentProps {
setValue: (value: number) => void;
}
function SubComponent({ setValue }: SubComponentProps) {
- const [subValue, setSubValue] = useState(0);
return (
<>
+ <p>subValue = {}</p>
<button onClick={() => setValue(0)}>subValue = 0</button>
<button onClick={() => setValue(1)}>subValue = 1</button>
<button onClick={() => setValue(2)}>subValue = 2</button>
</>
);
}
export default SubComponent;
SubComponentコンポーネント上でもAppコンポーネントで管理する値を表示したくなる場合もあるかもしれません.そのときはinterfaceを変更して値を受け取れるようにします.
import "./App.css";
interface SubComponentProps {
setValue: (value: number) => void;
+ value: number;
}
+function SubComponent({ setValue, value }: SubComponentProps) {
return (
<>
+ <p>subValue = {value}</p>
<button onClick={() => setValue(0)}>subValue = 0</button>
<button onClick={() => setValue(1)}>subValue = 1</button>
<button onClick={() => setValue(2)}>subValue = 2</button>
</>
);
}
export default SubComponent;
SubComponentコンポーネントの変更に合わせて,Appコンポーネントから値を渡せるようにします.
import { useState } from "react";
import "./App.css";
import SubComponent from "./SubComponent";
function App() {
const [appValue, setAppValue] = useState(0);
return (
<>
<p>appValue = {appValue}</p>
+ <SubComponent setValue={setAppValue} value={appValue} />
</>
);
}
export default App;

