Reactで無理やり関数コンポーネントの親子間のprops受け渡しをしてみた

Reactで親コンポーネントから子コンポーネントへ値を渡すのは以下のようすれば十分だったが、子コンポーネントから親コンポーネントに値を渡す方法がわからなかったので調べてみた。

import React from 'react';

const App = () => {
  const greeting = 'Hello Function Component!';
  // 子コンポーネントにvalueをセット
  return <Headline value={greeting} />;
}

// valueをFunctionComponentの引数として使用する設定
const Headline:React.FunctionComponent<{value: any}> = ({ value }) => {
  // valueを表示
  return <h1>{value}</h1>;
}

export default App;

コンポーネントから親コンポーネントに値を渡す方法とはつまり、vueでいうこんな感じのテクニック。 API - Vue.js vm.$emit( eventName, […args] )

// 子コンポーネントからemit
// 第一引数が子コンポーネントに設定した要素名(親のテンプレートに@をつけて設置する)で、第二引数がコールバックの引数になる
this.$emit('method', "this is argument")

// 親コンポーネントで受け取り、コールバック関数を実行
<template>
  <div>
    <ChildComponent @method="callback"/>
  </div>
</template>
<script>
// 省略
  callback(argument) {
    console.log(argument) // this is argument
  }
// 省略
</script>

結論から言って、Reactには子コンポーネントから親コンポーネントへ値を渡す方法はないらしい。 では、子から親へ値を渡して、子の変更時に親の方にも連動する変更を行いたい場合にはどうすれば良いのか......?

A. 親コンポーネントの関数を子コンポーネントへ渡し、子コンポーネントでその親の関数を実行する。

propsでやりとりするのではなく、関数を実行してpropsが必要な状況自体が必要ないようにするって考えておけばいいのだろうか。 それでもpropsが必要なんだが。。。みたいな状況になったら、つまりそれはReactでの開発思考的に間違った設計になっているだけの話なのかもしれない:thinking:

やっていることは親コンポーネントが子コンポーネントにpropsを渡しているのと変わりないが、渡しているものが親コンポーネントと繋がっている(実際に実行して確認してないので、コピペするだけではエラーが出るかもしれません)。

// parent
const App = () => {
  const [flag, setFlag] = React.useState(false)
  function switchFlag() {
    setState(true) // flag = true
  }
  // 子コンポーネントにswitchFlag関数をセット
  return (
    <div>
      <ChildComponent switchFlag={switchFlag}/>
    </div>
  )
}

// child
// switchFlag関数をFunctionComponentの引数として使用する設定
const ChildComponent:React.FunctionComponent<{switchFlag: any}> = ({switchFlag}) => {
  // switchFlagをボタンとして設置
  return (
    <div>
      <button onClick={switchFlag}>Click</button>
    </div>
  )
}

この状態でボタンを押すと、親コンポーネント側の関数が実行され、親コンポーネントのstateであるflagがtrueに変わる。 子コンポーネントでボタンが押されたときになんらかの処理を行ってから、そのあとにswitchFlag()で親コンポーネントの関数を実行するのものオッケー(下みたいな感じで):ok_hand_tone2:

// child
const ChildComponent:React.FunctionComponent<{switchFlag: any}> = ({switchFlag}) => {
  function onClickHandler() {
    // なんらかの処理
    switchFlag() // 親コンポーネントのswitchFlag関数の実行
  }
  return (
    <div>
      <button onClick={onClickHandler}>Click</button>
    </div>
  )
}

ここのページが参考になりました。:point_down_tone2::point_down_tone2::point_down_tone2: How to pass Props from child to parent Component? React Function Component: Callback Function