へなちょこSEの考察

0x22歳のへなちょこSEが、日々思うことを考察します。自社内、金融系を経て現在法人系PKG開発に従事。

Reactで親子間の制御をする方法

Reactを試してみていて、親子間で制御をする方法に困っていろいろ調べたので簡単にメモ。

やりたかったこと

Material UIを使ってモーダル的なDialogを表示したり閉じたりしたかった。

公式サイトのやり方だと子供(つまりDialog側)のコンポーネントに開いたり閉じたりするイベントを設定していたんだけど、親のコンポーネントから開いて子供のコンポーネントで閉じるようにしたかった。

(親の何かのボタンを押すと開いて、Dialog側の閉じるボタンで閉じる感じ)

試したこと

refなる仕組みを使ってやろうとした。

最初は親のほうで子供をref指定して子供のOpenメソッドを呼び出すことで子供のStateを更新して実現した。

けど、これだとMaterial UIのwithStylesを使って子どものコンポーネントをexportすると動かなくなる。

最終的に

「Dialogを開いている状態(Visible)」は子供が持つべきだと思ってたんだけど、「Dialogを開くべきかどうか」は親が判断するわけだから親のStateに持たせてもいいのか、と思い直して、以下のようになった。

  • 親のStateにVisibleを設定
  • Closeするfunction(setState({visible:false}))を追加
  • 子供のPropsとして親のVisibleとCloseFunctionを渡す
  • 閉じたいときは子供がPropsで渡ってきたCloseFunctionを実行することで親のStateを変更して閉じる

実装

親のState

state = { dialogOpen: false }

親のOpenFunction(ボタン押してDialog開く操作)

handleClose = () => {
    this.setState({ dialogOpen: false });
};

親のCloseFunction(Dialogの閉じるボタンが押された際に実行される)

handleClose = () => {
    this.setState({ dialogOpen: false });
};

親側の子供の呼び出し(JSX)

<MyDialog open={this.state.dialogOpen} close={this.handleClose}/>

子供側のDialogの表記

<Dialog
   open={this.props.open}
   onClose={this.props.close}
   scroll='paper'
   aria-labelledby="scroll-dialog-title"
>

子供側の閉じるボタン

<Button onClick={this.props.close} color="primary">Cancel</Button>

基本的に、親から子供の状態やら中身をいじりたければ親のStateに設定して子供はそれをPropで受け取って使えばいいらしい。

少なくとも、これでやりたかったことは実現できた。

当たり前のことなのかもしれないけど、調べるのに時間がかかったので同じことに悩む人のために記録を残しておきます。