🎃

useFormikでsubmitボタンが複数ある場合のイベント制御

2021/11/23に公開1

React でのフォームの管理に Formik を使用しています。
1つのフォームに submit ボタンが2つある場合、どのように onSubmit イベントを制御したら良いかわからなかったので調べた時の備忘録になります。

前提

  • <Formik> コンポーネントを使用せずに useFormik() カスタムフックをを使用します。
  • Typescript を使用します。
  • import 文や細かいところは省略します。

やりたいこと

以下のように form に2つのサブミットボタンがあり、それぞれ異なる関数を実行したいです。

export default function HogeComponent(props: Props): React.ReactElement {
	const onSubmit1 = (values: HogeInterface): void => {
		// ボタン1をクリックしたら実行する
	};
	const onSubmit2 = (values: HogeInterface): void => {
		// ボタン1をクリックしたら実行する
	};
	
	const formik = useFormik({
		initialValues,
		onSubmit: onSubmit1,  // ここをボタンによって切り替えたい!
	});
	return (
		<form onSubmit={formik.handleSubmit}>
			<TextField />
			<Button type="submit">ボタン1</Button>
			<Button type="submit">ボタン2</Button>
		</form>
	);
}

解決方法

ボタンの onClick イベント時に state に値をセットし、onSubmit のタイミングで値によって実行する関数を分岐するようにしました。

手順

  1. ボタンの onClick イベント時に値をセットする

    ボタンの onClick イベント時にボタン名を setState するようにします。
    React Hooks の useState を使用します。

import React, { useState } from 'react';

export default function HogeComponent(props: Props): React.ReactElement {
	const [buttonName, setButtonName] = useState<string>('');
<Button
	type="submit"
	onClick={(): void => setButtonName('button1')}>
	ボタン1
</Button>
<Button
	type="submit"
	onClick={(): void => setButtonName('button2')}>
	ボタン2
</Button>
  1. formik の onSubmit でボタンの値によって分岐させる関数を追加する
const onSubmit = (values: HogeInterface): void => {
	if (buttonName === 'button1') {
	    onSubmit1(values);
	} else if (buttonName === 'button2') {
	    onSubmit2(values);
	}
};
const formik = useFormik({ initialValues, onSubmit });

最終的にこうなりました

export default function HogeComponent(props: Props): React.ReactElement {
	const [buttonName, setButtonName] = useState<string>('');
	
	const onSubmit1 = (values: HogeInterface): void => {
		// ボタン1をクリックしたら実行する
	};
	const onSubmit2 = (values: HogeInterface): void => {
		// ボタン1をクリックしたら実行する
	};
	
	const onSubmit = (values: HogeInterface): void => {
		if (buttonName === 'button1') {
		    onSubmit1(values);
		} else if (buttonName === 'button2') {
		    onSubmit2(values);
		}
	};
	
	const formik = useFormik({ initialValues, onSubmit });
	
	return (
		<form onSubmit={formik.handleSubmit}>
			<TextField />
			<Button
				type="submit"
				onClick={(): void => setButtonName('button1')}>
				ボタン1
			</Button>
			<Button
				type="submit"
				onClick={(): void => setButtonName('button2')}>
				ボタン2
			</Button>
		</form>
	);
}

最後に

他にもいろいろと方法があるかもしれません。
もっと良いやり方があればご教示ください。

参考:

2 submit buttons

Discussion