💿
Remixで一覧から何かを削除→再取得→覧を更新する方法
背景
具体的にはfetcher.submit
でDELETEした後に何らかの方法で再取得処理を行うことで削除したものを一覧から表示させないようにしたい。
愚直に書こうにもfetcherはawaitできないので再取得を削除前に行ってしまう。
う〜ん、ベストプラクティスを知りたい...。
// 失敗例
onClick={() => {
await fetcher.submit({ id: 1 }, { action: "/users/delete", method: "POST" });
fetcher.load('/users')
}}
削除処理が終わったことをどう知るか
ここらへんを見ると、useEffect
を使って特定の状態になった時に何かしらを実行することが推奨されているっぽい。
結論
@coji さんコメントありがとうございます🙏🏻
action実行後にloaderを実行してくれるとのことで何もしなくても大丈夫でした。
他のページのactionを実行してもloaderが実行されるようで便利。
(これで動かなかった気がするけど当時のコード覚えておらず...)
Remixではこのようにaction関数の結果にかかわらず、すべてのアクティブなloaderを再検証しますが、オプトアウトするには以下のよう shouldRevalidate を利用する。
export const loader = () => {
return json({ null });
};
// このルートでは常に再検証を行わない
+ export const shouldRevalidate = () => false;
結論(ボツ)
fetcher.load()
とかで良いのかと思ったけど、以下を見ると2つの方法があった。
2つ目を採用した。
// 1つ目
const navigate = useNavigate()
navigate('.', { replace: true })
// 2つ目
const revalidator = useRevalidator();
import { useEffect } from "react";
import { DeleteRounded } from "@mui/icons-material";
import { IconButton } from "@mui/joy";
import {
Outlet,
useFetcher,
useLoaderData,
useRevalidator,
useRouteError,
} from "@remix-run/react";
function Layout() {
const fetcher = useFetcher();
function onDelete(id: number) {
fetcher.submit({ id }, { action: "/users/delete", method: "POST" });
}
const revalidator = useRevalidator();
useEffect(() => {
if (fetcher.data && fetcher.formAction === "/users/delete") { // 削除を検知
revalidator.revalidate(); // ここで再取得
}
}, [fetcher.data, fetcher.formAction, revalidator]);
return (
<div>
<tbody>
<tr>
<td>
<IconButton
size="sm"
variant="plain"
color="danger"
onClick={() => onDelete(1)} // 削除ボタンをクリック
>
<DeleteRounded />
</IconButton>
</td>
</tr>
</tbody>
</div>
);
}
Discussion
route の action 実行すると remix が勝手に loader を再実行してくれるので、ただそれをそのまま表示するだけで良いのでは。
公式だとここに書いてありますね
なんだか最初再fetchしてくれなかった気もするんですが全然ちゃんと動きますね...。いらぬ記事を作ってしまいました。。
ありがとうございます!記事更新しました🙇🏻♂️