LoginSignup
4
0

More than 5 years have passed since last update.

特定のReactコンポーネントの子要素に親要素からpropsを暗黙的に渡す方法

Last updated at Posted at 2018-03-20

複数のコンポーネントをワンセットで使いたい/使わせたい場面はしばしばあります。例えばTable関連のコンポーネントは、それぞれ別々に定義したほうが使い勝手は良いですが、tableタグの子要素や孫要素で発生したイベントなどはまとめてtableタグのpropsに渡すハンドラで処理したくなります。ここでは話を単純にするために、2階層の以下のような場面を想定します。

example1
export default class App extends React.Component {
  render() {
    return (
      <TableBody
        onRowSelection={rows => {console.log(rows)}}
      >
        {this.props.users.map((user, i) => {
          return (
            <TableRow key={user.id}>
              <TableRowColumn>{user.id}</TableRowColumn>
              <TableRowColumn>{user.name}</TableRowColumn>
              <TableRowColumn>{user.email}</TableRowColumn>
            </TableRow>
          );
        })}
      </TableBody>
    );
  }
}

TableBodyはtbodyタグを、TableRowはtrタグを、TableRowColumnはtdタグをそれぞれラップしています。TableRowで発生したなんらかのイベントをTableBodyのpropsに渡したonRowSelectionハンドラで処理しているとします。

具体的には以下のようにします。

example2
class TableBody extends React.Component {
  static displayName = "TableBody";

  public render() {
    return (
      <tbody>
        {React.Children.map(this.props.children, (child, i) => {
          if (
            !React.isValidElement(child) ||
            child.type.displayName !== TableRow.displayName
          ) {
            console.warn(`Children of the TableBody component must be TableRow`);
            return;
          }
          return React.cloneElement(
            child as React.ReactElement,
            {
              rowNumber: i,
              onRowSelection: (isChecked, rowNumber) => {
                this.props.onRowSelection(isChecked, rowNumber);
              },
            }
          );
        })}
      </tbody>
    );
  }
}

class TableRow extends React.Component {
  static displayName = "TableRow";

  render() {
    return (
      <tr>
        <td>
          <input type="checkbox" onChange={e => {
            this.props.onRowSelection(e.target.checked, this.props.rowNumber);
          }} />
        </td>
        {this.props.children}
      </tr>
    );
  }
}

ReactのChildren.mapメソッドでchildrenをループで検査して、propsを渡したいコンポーネントならcloneElementでpropsを追加します。Reactコンポーネントにstaticメンバを追加すると、親要素からchild.type.displayNameのようにアクセスできるので、それでコンポーネントを特定します。用意したコンポーネント以外を子要素に入れられたくない場合は、console.warnなどで警告を出してあげると親切です。

4
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
0