pookチームのtakepoです。
今回は、React × Redux でstateを変更する時にダイアログ等で確認表示を挟みたいときの良い方法をご紹介します。
その場合の例として、「ユーザーの情報を更新するとき、更新しても良いかを一度確認するダイアログ表示する」といったことが挙げられます。
この方法を一言で言うと、
「Container側では変更処理をするactionのみ呼び出すようにする」
です。
サンプルを交えてご紹介します。
サンプル
データを更新する際に確認用のダイアログを表示し、「OK」を選択した場合に更新処理を行います。
Dialog Component
ダイアログのcomponentはこのような形で作成しておきます。
※今回はMaterial-UIを使用し、シンプルな作りにしています。
class Dialog extends Component { props: { openFlag: boolean; message: string; title: string; okClickHandler: Function; }; renderDialogButtons(): React.Element<*> { return ( <div> <RaisedButton label="キャンセル" onClick={/* ダイアログを閉じる処理 */} /> <RaisedButton label="OK" onClick={this.props.okClickHandler} /> </div> ); } render() { return ( <Dialog title={this.props.title} open={this.props.openFlag} actions={this.renderDialogButtons()} > {this.props.message} </Dialog> ); } } export default Dialog;
更新処理をするactionを呼ぶContainer
変更処理をかけるactionを呼ぶ箇所はこのように書きます。
ここで注目したいポイントは、更新処理をするactionの第2引数にmeta情報としてダイアログのpropsに渡すmessageとtitleを入れておくことです。
const payload = { // 更新する情報 } const meta = { dialogInfo: { title: '更新', message: '情報を更新しますがよろしいですか?', }, } // 更新処理をかけるaction this.props.actions.update(payload, meta);
middleware
更新処理をするactionでmetaとして入れ込んだダイアログの情報を元に、ダイアログを開くときに必要なpayloadを作成します。そして、ダイアログを開くためのactionをnext()に渡します。
ここで注目したいポイントは、payloadのokClickHandlerに本来の変更処理を行うactionを入れ込むことです。
export default (store: any) => (next: any) => (action: any) => { if (action.meta && action.meta.dialogInfo) { const payload = { ...action.meta.dialogInfo, okClickHandler: () => { // このままactionを渡すとまた確認ダイアログを挟んでしまうので、dialogInfoを削除しておく delete action.meta.dialogInfo; next(action); }, }; // open() はダイアログを開くaction return next(open(payload)); } return next(action); };
まとめ
省いてしまっている部分もありますが、流れとしてはこのようになります。
middlewareをうまく利用することで
「Container側では変更処理をするactionのみ呼び出すようにする」
ことができました。
これで更新処理を呼ぶ側をすっきり書くことができます!