表題の通りだが。メモ。
事象
Remixアプリである画面を作った。その画面ではaction()でサーバー処理した後、そのまま自画面に戻るという仕様を実装していた。具体的にはaction()の最後でreturn redirect('/hogehoge');を実行していた。
export async function action({request}:ActionFunctionArgs) {
// サーバー処理もろもろ
// ...
// ...
return redirect('/hogehoge'); // 自画面のパス指定してまた同じ画面に戻ってくる
}
export default function Page() {
return (
<div>
<Form method="POST">
<div>
<label>text:</label>
<input type="text" name="text"/>
</div>
<div>
<label>amount:</label>
<input type="number" name="amount"/>
</div>
<div>
<button type="submit">
submit
</button>
</div>
</Form>
</div>
)
}
そしたら前画面で入力していた値が自画面遷移後も入力済のまま残ってしまった。

あくまで一例だが、こんな感じ↑で入力していたFormの値がredirectで戻ってきた後もそのまま入力済の状態で残存してしまう。で、この初期入力済の状態を排除したい(リセットしたい)、という話。
対処
formにkeyパラメータを付ける。これによりRemixがReact Componentの再マウントを行ってくれるので、自画面遷移後にはフィールドの値がリセットされる。
ただし、keyが固定値だと、結局同じ現象になるので、keyの値を動的な値にしなければならない。じゃあクライアント側でconst key = String(new Date().getTime());とかやればいいかと思ったが、これだと最初は良くても次の表示時にHydrationのエラーになる(まあそりゃそうか、、、)
// ... 略
export default function Page() {
// この例は失敗します
const key = String(new Date().getTime());
return (
<div>
<Form method="POST" key={key}>
<div>
<label>text:</label>
<input type="text" name="text"/>
</div>
<div>
<label>amount:</label>
<input type="number" name="amount"/>
</div>
<div>
<button type="submit">
submit
</button>
</div>
</Form>
</div>
)
}
というわけで仕方ないのでloader()(つまりサーバーサイド)でkeyに用いる一意な値を振り出してクライアント側に渡してそれを使うことにする。こんな感じ:
export async function loader({request}:LoaderFunctionArgs) {
const key = String(new Date().getTime());
// その他サーバー処理もろもろ
// ...
return {key, hogehoge};
}
export async function action({request}:ActionFunctionArgs) {
// サーバー処理もろもろ
// ...
// ...
return redirect('/hogehoge'); // 自画面のパス指定してまた同じ画面に戻ってくる
}
export default function Page() {
const data = useLoaderData<typeof loader>();
return (
<div>
<Form method="POST" key={data.key}>
{/*
中略
*/}
</Form>
</div>
);
}
で、とりあえず事象は回避できた。
もう少しスマートなやり方はありそうだが(というのも、この仕様のために僅かながらとはいえサーバー側の処理が加わるのが個人的に解せないのである)、小手先のオプションなんかでは解決しなかったし、かといってuseEFfectとかuseNavigationとか使ってクライアント側でゴチャゴチャと小細工するのもやりたくなかったので、まあこのくらいで済むならこれでいいかと思うことにした。他のやり方知ってる人いたら教えてください。