個人的な議事録です。
環境
- react: 17.0.2
- next: 11.1.3
やりたいこと
- 動的に高さの変わるページへhash値を渡して、ページを遷移後に指定位置にスクロールさせたい
試してダメだったこと
- 遷移前の component に next/link で hash を渡す
一覧のcomponent
import NextLink from 'next/link';
// 省略
const UserListComponent = () => {
return (
<NextLink
href={{
pathname: `/user/${id}`,
hash: 'scroll',
query: {
hoge: hoge,
},
}}
passHref
/**
* ページの先頭にならないように、false にしてみた
* @see https://nextjs.org/docs/api-reference/next/link
*/
scroll={false}
>
<p>
Moves to user details page
</p>
</NextLink>
)
}
スクロールさせたいcomponent
// 省略
const FormComponent = () => {
return (
<div id={'scroll'}>ここまでスクロールしてほしい</div>
)
}
- これだと スクロールさせたい DOM が生成される前なので、場所を把握できずスクロールしなかった
指定位置までスクロールできたコード
- スクロールさせたい component のレンダリング後に、自身で hash を追加するとキレイにスクロールした
- 流れとしては以下の通り
- fetch 後に動的な component を描画
- スクロールさせたい component のレンダリング後、初回だけ router.replace で hash を追加
fetch
export const useUser = (id: string) => {
// 省略
const { data, error } = useSWR(`/api/user/${id}`, fetcher)
return {
user: data,
error,
isLoading: !error && !data,
}
};
一覧のcomponent
import NextLink from 'next/link';
// 省略
const UserListComponent = () => {
return (
<NextLink
// ここで hash を追加しても意味ないので、今回はなし
href={{
pathname: `/detail/${id}`,
query: {
hoge: hoge,
},
}}
passHref
>
<p>
{text}
</p>
</NextLink>
)
}
親component
// 省略
const { user, error, isLoading } = useUser(id)
// fetch前に component が表示されてしまうと、位置がズレるため、親component で fetchData があれば、完了するまで表示させない
if(isLoading) {
return null;
}
const ProfileComponent = () => {
return (
// 動的に生成される component
<InformationComponent />
// スクロールさせたい component
<formComponent />
)
}
スクロールさせたいcomponent
// 省略
/**
* useEffect 内で(レンダリング後に) hash を追加する
*/
useEffect(() => {
// history に追加しないように router.replace
router.replace({ hash: 'scroll' }, undefined, { shallow: true });
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const FormComponent = () => {
return (
<div id={'scroll'}>ここまでスクロールできた</div>
)
}