背景
クマの出没場所を全国規模で登録できるアプリを作成中の事象です。
下のgifのように、スクロールバーが表示されるDrawerメニューを実装したところ、下までスクロール → 登録ボタン押下 → 再表示時した後に、先頭に戻らせたい…という願望が生じました。
(登録したデータはテスト環境のもので、実際に起きたことではありません)
動作環境
- node.js ver 18.18.2
- next.js ver 14.0.3
- react ver 18
- mui/material ver 5.16.7
試したこと
- Drawerの初期表示時に
scrolTo
でトップに戻させる - 閉じるボタン、登録ボタンを押したときに、
scrllTo
でトップに戻させる
いずれも再表示時、トップに戻るようにはなりませんでした。同期処理で表示 → スクロール の順序を確定させれば可能かもしれませんが、そこまで難しく考えたくない…という願望もありました。
解決策
keyを用いたコンポーネントの再レンダリングを利用します。
参考:https://ja.react.dev/learn/preserving-and-resetting-state#resetting-a-form-with-a-key
type Props = {
onRegisterClick: () => void;
onClose: () => void;
};
export function PlaceDrawer(props: Props) {
const drawerKey = useRef<number>(0);
return (
<>
<Drawer key={drawerKey.current}>
<Box>
<Grid container spacing={2} sx={{ marginTop: "24px" }}>
<Grid item xs={6}>
<Button
onClick={() => {
props.onClose();
// HACK: クリック時にスクロールをトップに戻すのが困難なため、コンポーネント自体の再レンダリングで対応
drawerKey.current = drawerKey.current + 1;
}}
>
地図に戻る
</Button>
</Grid>
<Grid item xs={6} sx={{ textAlign: "right" }}>
<Button
onClick={async () => {
props.onRegisterClick();
// HACK: クリック時にスクロールをトップに戻すのが困難なため、コンポーネント自体の再レンダリングで対応
drawerKey.current = drawerKey.current + 1;
}}
>
登録する
</Button>
</Grid>
</Grid>
</Box>
</Drawer>
</>
);
}
keyが変更された際、コンポーネントは再レンダリングされる(違うものとして扱われる)ため、 PlaceDrawer
が再表示された時には先頭に戻った状態になります。
再レンダリングがパフォーマンスに影響を与える可能性(要検証)もありますが、個人開発のレベルであれば上のような方法でも良いのかなと思います。