0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Remix】redirectで自画面に戻ってくる際に前画面で入力していた値が残存する現象への対処

Posted at

表題の通りだが。メモ。

事象

Remixアプリである画面を作った。その画面ではaction()でサーバー処理した後、そのまま自画面に戻るという仕様を実装していた。具体的にはaction()の最後でreturn redirect('/hogehoge');を実行していた。

/app/routes/hogehoge.tsx
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>
    )
}

そしたら前画面で入力していた値が自画面遷移後も入力済のまま残ってしまった。
image.png

あくまで一例だが、こんな感じ↑で入力していたFormの値がredirectで戻ってきた後もそのまま入力済の状態で残存してしまう。で、この初期入力済の状態を排除したい(リセットしたい)、という話。

対処

formkeyパラメータを付ける。これによりRemixがReact Componentの再マウントを行ってくれるので、自画面遷移後にはフィールドの値がリセットされる。

ただし、keyが固定値だと、結局同じ現象になるので、keyの値を動的な値にしなければならない。じゃあクライアント側でconst key = String(new Date().getTime());とかやればいいかと思ったが、これだと最初は良くても次の表示時にHydrationのエラーになる(まあそりゃそうか、、、)

/app/routes/hogehoge.tsx
// ... 略
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に用いる一意な値を振り出してクライアント側に渡してそれを使うことにする。こんな感じ:

/app/routes/hogehoge.tsx
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とか使ってクライアント側でゴチャゴチャと小細工するのもやりたくなかったので、まあこのくらいで済むならこれでいいかと思うことにした。他のやり方知ってる人いたら教えてください。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?