如何在类组件中使用 next.js 中的“useRouter()”?

Posted

技术标签:

【中文标题】如何在类组件中使用 next.js 中的“useRouter()”?【英文标题】:How to use "useRouter()" from next.js in a class component? 【发布时间】:2019-11-23 10:21:40 【问题描述】:

我试图通过使用来自“next/router”的useRouter() 并使用该ID 从我的服务器获取一些数据来从我的url 模式(如localhost:3000/post?loc=100)中获取查询。当我在无状态功能组件中使用它时,它起作用了。

然后页面显示“无效的挂钩调用”。我尝试调用无状态功能组件的getInitalProps(),但它在那里也不起作用并显示相同的错误。 使用这种方法有什么规则吗?

我正在使用 React 库和 Next.js 框架开发前端。

constructor(props) 
  this.state = 
    loc: useRouter().query.loc,
    loaded: false
  ;

【问题讨论】:

This 对话可能有用,但似乎useRouter 功能仍处于试验阶段。 您通常可以从 getInitialProps 生命周期中收到的上下文值访问位置信息。 How can I use React hooks in React classic `class` component?的可能重复 【参考方案1】:

钩子只能在功能组件内部使用,不能在类内部使用。我建议按照 next.js 文档使用withRouter HOC:

使用useRouter 挂钩,或withRouter 用于类组件。

如果您想切换到挂钩,请参阅From Classes to Hooks。


一般来说,可以创建一个包装函数组件,通过 props 将自定义钩子传递给类组件(但在这种情况下没有用):
const MyClassWithRouter = (props) => 
  const router = useRouter()
  return <MyClass ...props router=router />


class MyClass...
  constructor(props) 
    this.state = 
      loc: props.router.query.loc,
      loaded: false
    ;
  

【讨论】:

新链接:nextjs.org/docs/api-reference/next/router#withrouter 因为自述文件的链接是outdated【参考方案2】:

withRouter 示例

https://***.com/a/57029032/895245 提到过,但像我这样的新手需要更多细节。更详细/直接的描述是:

功能组件:

import  useRouter  from "next/router";

export default function Post() 
  const router = useRouter();
  return (
    <div> router.query.id </div>
  )

类组件等效:

import  withRouter  from 'next/router'
import React from "react";

export default withRouter(class extends React.Component 
  render() 
    return (
      <div> this.props.router.query.id </div>
    )
  
)

我对此进行了更具体的测试,如下所示。首先,我使用了vercel/next-learn-starter/basics-final/pages/posts/[id].js,然后破解了它以使用路由器:

diff --git a/basics-final/pages/posts/[id].js b/basics-final/pages/posts/[id].js
index 28faaad..52954d3 100644
--- a/basics-final/pages/posts/[id].js
+++ b/basics-final/pages/posts/[id].js
@@ -4,13 +4,17 @@ import Head from 'next/head'
 import Date from '../../components/date'
 import utilStyles from '../../styles/utils.module.css'
 
+import  useRouter  from "next/router"
+
 export default function Post( postData ) 
+  const router = useRouter();
   return (
     <Layout>
       <Head>
         <title>postData.title</title>
       </Head>
       <article>
+        <div>router.query.id = router.query.id</div>
         <h1 className=utilStyles.headingXl>postData.title</h1>
         <div className=utilStyles.lightText>
           <Date dateString=postData.date />

然后,我将其运行为:

git clone https://github.com/vercel/next-learn-starter
cd next-learn-starter
git checkout 5c2f8513a3dac5ba5b6c7621d8ea0dda881235ea
cd next-learn-starter
npm install
npm run dev

现在当我访问:http://localhost:3000/posts/ssg-s-s-r 我看到:

router.query.id = ssg-s-s-r

然后我将其转换为等效的类:

import Layout from '../../components/layout'
import  getAllPostIds, getPostData  from '../../lib/posts'
import Head from 'next/head'
import Date from '../../components/date'
import utilStyles from '../../styles/utils.module.css'

import  withRouter  from 'next/router'
import React from "react"


export default withRouter(class extends React.Component 
  render() 
    return (
      <Layout>
        <Head>
          <title>this.props.postData.title</title>
        </Head>
        <article>
          <div>router.query.id = this.props.router.query.id</div>
          <h1 className=utilStyles.headingXl>this.props.postData.title</h1>
          <div className=utilStyles.lightText>
            <Date dateString=this.props.postData.date />
          </div>
          <div dangerouslySetInnerhtml= __html: this.props.postData.contentHtml  />
        </article>
      </Layout>
    )
  
)

export async function getStaticPaths() 
  const paths = getAllPostIds()
  return 
    paths,
    fallback: false
  


export async function getStaticProps( params ) 
  const postData = await getPostData(params.id)
  return 
    props: 
      postData
    
  

一切似乎都没有改变。

在 Next.js 10.2.2 上测试。

【讨论】:

【参考方案3】:

编写您的组件,然后使用withRouter(YourClassName) 将其导出 喜欢:

class App extends React.Component
   render()
        <h2> this is an example router query params : this.props.router.query.id <h2/>
     

export default withRouter(App)

所以你可以像上面的例子一样从组件的 prop 访问路由器 :)

【讨论】:

以上是关于如何在类组件中使用 next.js 中的“useRouter()”?的主要内容,如果未能解决你的问题,请参考以下文章

如何忽略 Next.js 组件中导致单元测试中的解析错误的 CSS 模块导入

如何从 Next.js 中的服务器获取 HOC 中的数据?

如何将可拖动属性传递给 Next.js Image 组件中的 <img>?

如何在 Next.js 组件中使用 SVG 图像?

如何在头组件中使用效果(ReactJS/Next.js)

如何从 Strapi API 引用 Next JS 中的图像组件?