80
79

More than 1 year has passed since last update.

【Next】動的なページへの遷移後に、指定の位置(hash)までスクロールさせたい

Last updated at Posted at 2022-07-27

個人的な議事録です。

環境

  • 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>
	)
}
80
79
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
80
79