🦁
useActionStateをForm以外で使用する
はじめに
React公式ドキュメントに記載されているuseActionStateの使用例は、<form />
で使用する例しか書いていない。
ただ、別にフォームじゃなくても使えるはずなので、それを調査した。
この記事では触れないこと
- useActionStateとは?
前提
ボタンをクリックして、useActionStateのformActionを呼び出すコンポーネントを作成して調査。
環境
"next": "15.0.4",
"react": "^19.0.0",
"react-dom": "^19.0.0",
調査結果1
ポイント
- useActionStateに指定した関数fnの第1引数には現在のstateが、第2引数にはformActionに渡した値が入るため、第2引数をサーバーに送るなり、取り回せばOK
注意
ボタンをクリックすると、一応動くが、エラーメッセージが出る。
(actionをtransition外で実行しようとしているため)
An async function was passed to useActionState, but it was dispatched outside of an action context. This is likely not what you intended. Either pass the dispatch function to an `action` prop, or dispatch manually inside `startTransition`
'use client';
import { useActionState } from 'react';
export default function Page() {
// クリックしたボタンの文字を2秒後に設定する
const [str, setStr, isPending] = useActionState(
// setStrに渡した値は、第2引数のnewValueに渡されるので、これを取り回せばOK
async (current: string, newValue: string) => {
// 2秒待つ
await new Promise((resolve) => setTimeout(resolve, 2000));
return newValue;
},
'initial value',
);
return (
<div>
<div>設定中の文字: {str}</div>
<div className="flex gap-2">
<button
type="button"
onClick={() => {
setStr('hoge');
}}
disabled={isPending}
>
hoge
</button>
<button
type="button"
onClick={() => {
setStr('fuga');
}}
disabled={isPending}
>
fuga
</button>
</div>
</div>
);
}
調査結果2(エラーを出ないようにした)
ポイント
- useActionStateのformActionを、startTransitionで囲う
'use client';
import { startTransition, useActionState } from 'react';
export default function Page() {
// クリックしたボタンの文字を2秒後に設定する
const [str, setStr, isPending] = useActionState(
// setStrに渡した値は、第2引数のnewValueに渡されるので、これを取り回せばOK
async (current: string, newValue: string) => {
// 2秒待つ
await new Promise((resolve) => setTimeout(resolve, 2000));
return newValue;
},
'initial value',
);
return (
<div>
<div>設定中の文字: {str}</div>
<div className="flex gap-2">
<button
type="button"
onClick={() => {
startTransition(() => setStr('hoge'));
}}
disabled={isPending}
>
hoge
</button>
<button
type="button"
onClick={() => {
startTransition(() => setStr('fuga'));
}}
disabled={isPending}
>
fuga
</button>
</div>
</div>
);
}
まとめ
- useActionStateから返されるformActionを実行することで、actionを実行できる。
- formActionに渡した値は、actionの第2引数に渡される
-
<form />
を使わない場合、startTransitionの内部で呼び出さないとエラーが起きる。- 上記の事例から、useActionStateは
<form />
以外での使用をあまり想定していないように感じるため、その場合はuseTransitionを使用するほうがベターかもしれない。
- 上記の事例から、useActionStateは
ASTRSK(astrsk.co.jp)は、スタートアップ・新規事業開発に強いシステム開発会社です。サービスやシステムの構築を得意としており、開発をはじめデザインやUXにおいても優れた経験と技術を有しています。
Discussion