子コンポーネントのイベントを親コンポーネントに渡す方法 – React.js

React.jsで子コンポーネントや孫コンポーネントで発生したイベントを親コンポーネントに伝える方法を解説します。

テーブルにある項目を「削除」ボタンを押したときにデータが削除される機能を考えてみます。

テーブルのデザインは material-ui から取得し、削除ボタンだけ追加しています。

参考デザイン:https://material-ui.com/components/tables/#caption

親コンポーネント(親要素)

親コンポーネントの定義を見てみましょう。useStateuseEffectを使ってステート(データ)の管理を行ない、子コンポーネントであるTableTestコンポーネントを呼び出しています。

../pages/test.js

import React, {useState, useEffect} from "react";
import TableTest from "../components/tableTest";

export default function Test(){
  const [dataList, setDataList] = useState([]);
  useEffect(() => {
    setDataList([
      {name: 'Frozen yoghurt', calories: 159, fat: 6.0, carbs: 24, protein: 4.0},
      {name: 'Ice cream sandwich', calories: 237, fat: 9.0, carbs: 37, protein: 4.3},
      {name: 'Eclair', calories: 262, fat: 16.0, carbs: 24, protein: 6.0}
    ]);
  } ,[]);
  return(
      <TableTest onRemoveData={name => { 
          const newDataList = dataList.filter(data => data.name !== name);
          setDataList(newDataList);
        }} 
        rows={dataList} />
  );
}

親コンポーネントのonRemoveDataに着目します。

name => { 
          const newDataList = dataList.filter(data => data.name !== name);
          setDataList(newDataList);
}

dataListを引数nameでフィルターし、フィルター後のデータをsetDataListで更新しています。

setDataListが実行されるとTestコンポーネント自体が再レンダリングされ、結果的に対象のデータが削除された状態となります。

全体としては、TabelTestコンポーネントに関数としてonRemoveDataを渡し、子コンポーネントであるTableListコンポーネントに引き渡した先の関数で引数nameを取得しています。

子コンポーネントであるTabelTestコンポーネントを見てみましょう。

子コンポーネント(子要素)

../components/tableTest.js

import {
  Table,
  TableBody,
  TableCell,
  TableContainer,
  TableHead,
  TableRow,
  Paper,
  Button,
} from '@material-ui/core';

export default function TableTest({ rows = [], onRemoveData = f => f}){
  return(
    <TableContainer component={Paper}>
      <Table aria-label="caption table">
        <caption>A basic table example with a caption</caption>
        <TableHead>
          <TableRow>
            <TableCell>Dessert (100g serving)</TableCell>
            <TableCell align="right">Calories</TableCell>
            <TableCell align="right">Fat&nbsp;(g)</TableCell>
            <TableCell align="right">Carbs&nbsp;(g)</TableCell>
            <TableCell align="right">Protein&nbsp;(g)</TableCell>
            <TableCell align="right">削除ボタン</TableCell>
          </TableRow>
        </TableHead>
        <TableBody>
          {rows.map((row) => (
            <TableRow key={row.name}>
              <TableCell component="th" scope="row">
                {row.name}
              </TableCell>
              <TableCell align="right">{row.calories}</TableCell>
              <TableCell align="right">{row.fat}</TableCell>
              <TableCell align="right">{row.carbs}</TableCell>
              <TableCell align="right">{row.protein}</TableCell>
              <TableCell align="right"><Button variant="contained" onClick={() => onRemoveData(row.name)} >削除</Button></TableCell>
            </TableRow>
          ))}
        </TableBody>
      </Table>
    </TableContainer>
  );
}

注目して欲しいのは次の二箇所です。

export default function TableTest({ rows = [], onRemoveData = f => f}){

引数のrowsでデータリストを取得しています。また、onRemoveDataで関数そのものを取得しています。onRemoveData = f => f とすることで、親コンポーネントで定義した関数の内容を子コンポーネントで実行できるようになるのです。

<TableCell align="right"><Button variant="contained" onClick={() => onRemoveData(row.name)} >削除</Button></TableCell>

引数で取得したonRemoveData関数をonClickイベントで実行しています。onRemoveData関数の引数にrow.nameを指定することで、親コンポーネントで定義した関数の引数nameにデータを渡しています。

このように、子コンポーネントでは関数の呼び出しだけを行い、親コンポーネントで実行する関数を定義することで、子コンポーネントのイベントを親コンポーネントに渡すことができます。

コメント

タイトルとURLをコピーしました