Next.js:当Next触发更改时,获取动态路由参数的正确方法.链接



我用Next.js构建了一个看板应用程序。我目前有两个板:

{"name": "New Board", "id": "6db0ceec-d371-4b53-8065-2eeebac4694a"}
{"name": "tired": "cc41d33e-43a1-49bd-8b76-18e46417b27a"}

我有一个菜单,它映射到下一个Link,呈现这样的链接:

<Link href={`/board/${board.id}`}>{board.name}</Link>

然后我有以下内容:

  • src/pages/board/[boardId].js(第页(
  • src/pages/api/board/[boardId].js(API终点(

在页面中,我定义了一个异步函数,它向检索数据的端点发送GET请求。对于SSR,它在getServerSideProps()中被调用(当用户从应用程序的另一部分导航到特定的板页时,会调用它(。对于客户端,我称之为效果。(当用户已经在电路板页面上,但他们从菜单中选择了不同的电路板时,会调用此命令(。

我遇到的问题是找出正确的Next.js惯用方法,以便在路由更改时从路由中获得新的id。我试过使用router.queryrouter.asPath。然而,它经常给我旧的值(在路线更改之前(。当路由更改时,我能够可靠地获得正确参数的唯一方法是使用window.location.pathname.split('/')[2]

我将包括该页面的源代码以及一些console.log((输出,它将显示当我通过单击菜单中的Links在两个板之间来回切换时,从路由获取id的三种方法是如何不一致的(窗口总是正确的(:

// src/pages/board/[boardId].js
import React, { useEffect, useState } from 'react'
import { useDispatch } from 'react-redux'
import supabase from 'Utilities/SupabaseClient'
import Board from 'Components/Screens/Board/Board'
import { useRouter } from 'next/router'
import axios from 'axios'
import { getBaseUrl } from 'Utilities'
import { hydrateTasks } from 'Redux/Reducers/TaskSlice'
const BoardPage = (props) => {
const router = useRouter()
const dispatch = useDispatch()
async function handleRouteChange() {
const { asPath } = router
const { boardId } = router.query // sometimes this does not update!
const idFromWindow = window.location.pathname.split('/')[2]
const { board, tasks } = await handleFetchData({boardId: idFromWindow})
console.log(`hello from handleRouteChange:nnFrom window: ${idFromWindow}nnFrom router.query: ${boardId}nnFrom router.asPath: ${asPath}`)
dispatch(hydrateTasks({board, tasks}))
}
useEffect(() => {
//subscribe
router.events.on('routeChangeComplete', handleRouteChange);
//unsubscribe
return () => router.events.off('routeChangeComplete', handleRouteChange);
}, [ router.events]);
return (
<Board {...props}/>
)
}
const handleFetchData = async ({boardId, req}) => {
const baseUrl = getBaseUrl(req)
return axios.get(`${baseUrl}/api/board/${boardId}`)
.then(({data}) => data)
.catch(err => { console.log(err)})
}
export async function getServerSideProps ({ query, req }) {
const { user } = await supabase.auth.api.getUserByCookie(req)
if (!user) {
return { props: {}, redirect: { destination: '/signin' } }
}
const { boardId } = query
const { board, tasks}  = await handleFetchData({boardId, req})
return { props: { user, board, tasks } }
}
export default BoardPage

从";累了";板,我在";新董事会";以及";"累了";。观察控制台输出。窗口总是正确的。路由器经常出错:

// click 1
[boardId].js?0a51:19 hello from handleRouteChange:
From window: 6db0ceec-d371-4b53-8065-2eeebac4694a
From router.query: cc41d33e-43a1-49bd-8b76-18e46417b27a
From router.asPath: /board/cc41d33e-43a1-49bd-8b76-18e46417b27a
// click 2
[boardId].js?0a51:19 hello from handleRouteChange:
From window: cc41d33e-43a1-49bd-8b76-18e46417b27a
From router.query: cc41d33e-43a1-49bd-8b76-18e46417b27a
From router.asPath: /board/cc41d33e-43a1-49bd-8b76-18e46417b27a

// click 3
[boardId].js?0a51:19 hello from handleRouteChange:
From window: 6db0ceec-d371-4b53-8065-2eeebac4694a
From router.query: cc41d33e-43a1-49bd-8b76-18e46417b27a
From router.asPath: /board/cc41d33e-43a1-49bd-8b76-18e46417b27a
// click 4
[boardId].js?0a51:19 hello from handleRouteChange:
From window: cc41d33e-43a1-49bd-8b76-18e46417b27a
From router.query: cc41d33e-43a1-49bd-8b76-18e46417b27a
From router.asPath: /board/cc41d33e-43a1-49bd-8b76-18e46417b27a

我是Next.js的新手,所以我可能走错了路。。。

我是如何做到这一点的-

假设我有一个名为localhost:3000/board 的页面

我已经用state完成了这项操作,而不是用[boardId](让我们把这个状态称为boardId,initialvalue为null(

假设应用程序中任何地方的用户使用链接访问此页面

<Link href="/board">
Go To Board
</Link>

在页面装载上,我试图从诸如-之类的url读取boardId的值

useEffect(() => {
if (router.query && router.query.boardId )
{ 
setBoardId(router.query.boardId);
}
}, []);

如果fout我设置了boardId的状态,我也这样做是为了从API 获得数据

useEffect(() => {
if (boardId) getBoardIdDataFromApi();
}, [boardId] );

在上述情况下,由于我没有将任何Id作为参数传递到url,因此板Id将为空。(在我的情况下,我在这里创建了一个新的板(

案例2-假设一个用户从页面中的任何地方访问这个板页面,并带有类似的内容-

<Link
href={{
pathname: "/board",
query: { boardId: boardId },
}}
> 

这次url会像一样

localhost:3000?boardId=AnyBoardId

这将加载Id并从api中获取实际数据,或者相应地更改布局。

useEffect(() => {
if (router.query && router.query.boardId )
{ 
setBoardId(router.query.boardId);
}
}, []);

案例-3

现在,当用户将boardId从页面本身更改为不在页面上时,您可以执行-

const onChangeBoard = (v) => {
router.push('/board?boardId=${v}', undefined, { shallow: true })
setboardId(v);
}

这将更新boardId的状态,并在用户选择不同的板并更新url后获取数据。

  • 我正在试验{shall:true},并且我在客户端拥有所有的数据获取机制

为您-

  1. 您可以为案例1阻止getServerSideProps
  2. 对情况2使用getServerSideProps
  3. 对于情况3,如果删除浅层,则可以再次使用getServerSideProps,但请验证

这可能不是确切的答案。但可以帮助您理解的逻辑

好的,我通过检查的效果来实现这一点

useEffect(() => {
async function handleRouteChange() {
const { boardId } = router.query
const { board, tasks } = await handleFetchData({ boardId })
dispatch(hydrateTasks({ board, tasks }))
}
handleRouteChange()
}, [router])

以下是页面的完整代码:

// src/pages/board/[boardId].js
import React, { useEffect } from 'react'
import { useDispatch } from 'react-redux'
import supabase from 'Utilities/SupabaseClient'
import Board from 'Components/Screens/Board/Board'
import { useRouter } from 'next/router'
import axios from 'axios'
import { getBaseUrl } from 'Utilities'
import { hydrateTasks } from 'Redux/Reducers/TaskSlice'
const BoardPage = (props) => {
const router = useRouter()
const dispatch = useDispatch()
useEffect(() => {
async function handleRouteChange() {
const { boardId } = router.query
const { board, tasks } = await handleFetchData({ boardId })
dispatch(hydrateTasks({ board, tasks }))
}
handleRouteChange()
}, [router])
return (
<Board {...props}/>
)
}
const handleFetchData = async ({boardId, req}) => {
const baseUrl = getBaseUrl(req)
return axios.get(`${baseUrl}/api/board/${boardId}`)
.then(({data}) => data)
.catch(err => { console.log(err)})
}
export async function getServerSideProps ({ query, req }) {
const { user } = await supabase.auth.api.getUserByCookie(req)
if (!user) {
return { props: {}, redirect: { destination: '/signin' } }
}
const { boardId } = query
const { board, tasks}  = await handleFetchData({boardId, req})
return { props: { user, board, tasks } }
}
export default BoardPage

最新更新