追記)Next.js10からはこの as
の件は必要なくなり、勝手に認識してくれるようになりました。
Next.jsにはDynamic Routesという機能があり、 posts/[id].js
のようなファイル名でページを作ると posts/12
のように動的なURLでアクセスできるページにすることができる。
しかし、このページに対してNext.jsの Link を使って <Link href="/posts/12">
のようにして遷移してみると、どうもSPAとしてアクセスできるのではなく、通常のリンクとしてのアクセスになってしまい、画面全体が読み込まれてSPAにならない(Next.js9.3現在)。
ではどうするのかというと下記のように as
を利用する。
<Link href="/posts/[id]" as="/posts/12">
つまり、実在する [id]
ページにアクセスするが、見た目上はasのURLにアクセスさせる、という意味。ドキュメントにも一応書かれてはいた。
as - The path that will be rendered in the browser URL bar. Used for dynamic routes
なんとなく、サーバーサイド、クライアント側のWebフレームワーク、例えばNuxt.jsにしろLaravelなどにしろ、作ったURLにそのままアクセスすればなんとなくいい感じにルーティングしてくれるのでその感覚でいると悩むことになる。Next.jsはちゃんと実際のURLと見た目上のURLを両方指定しなければいけない。恐らくNext.js的にも「そんなURLないけど?」という感じで単なるリンクにしてしまうのだろう。
これはこれで良いとして、useStateを使っている場合は別の問題が発生する。例えば、動的URLのパラメータを取得するのには下記のようにrouterを利用する。
const router = useRouter()
return <div>{router.query.id}</div>
これは別に良いのだが、違うパラメータの同じページ、例えば posts/11
から posts/12
にアクセスする場合、この間にuseStateが混ざっているとうまくいかなくなる。
const router = useRouter()
const [post, setPost] = useState(getPost(router.query.id))
return <div>{post.name}</div>
画面遷移後にrouterの値自体はもちろんちゃんと変わるのだが、useStateから取得している値は変わらない。もちろんこれはsetしていないから。元々は完全なページ切り替わりによって全てがリセットされていたのでちゃんと全てが新しいデータに切り替わっていたが、ちゃんとSPAできるようになると今度はルーティングのパラメータ以外は何も変わらなくなり、両方の値を使って表示をしているとなんかぐちゃぐちゃになる。
ということで、ルーティングのパラメータが変わった場合は、また改めて手動で値をセットし直さなければならない。具体的にはuseEffectを使って下記のようにする。
const router = useRouter()
const [post, setPost] = useState(getPost(router.query.id))
useEffect(() => {
setPost(getPost(router.query.id))
}, [router.query.id])
return <div>{post.name}</div>
このようにして、idが変わったらデータを取り直す、という処理を入れる。もしpostに紐づくcommentsも取得している、ということであればそちらなども全部取得してsetし直す必要がある。コンポーネントの最初で色々連動させてuseStateしているからといって勝手に連動してくれたりはしない。
Crieitは誰でも投稿できるサービスです。 是非記事の投稿をお願いします。どんな軽い内容でも投稿できます。
また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!
こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください。
ボードとは?
コメント