Next.JS“比上一次渲染时渲染了更多的钩子”

Posted

技术标签:

【中文标题】Next.JS“比上一次渲染时渲染了更多的钩子”【英文标题】:Next.JS "Rendered more hooks than during the previous render" 【发布时间】:2020-11-26 14:43:02 【问题描述】:

我目前正在实施 useSWR,以便从我的 express 和 mongo-db 后端获取数据。我能够从数据库中成功获取数据没问题。以下是我用来实现此目的的代码:

```//SWR method for hydration
const fetcher = (...args) => fetch(...args).then(res => res.json())
const  data, error  = useSWR('http://localhost:3000/appi/daily', fetcher)
if (error) return <div>failed to load</div>
if (!data) return <div>loading...</div>```

然后使用以下命令访问:

data.currentInfo.username 其中用户名是集合中的字段之一。

当我尝试将此信息添加到状态钩子中时出现问题,然后返回的错误呈现的钩子比上一次渲染时更多。

删除线: const[displayNumber] = useState(data.currentInfo.randomString) 并且任何使用状态变量 displayNumber 的行都会完全修复错误。

我已经在下面包含了相关代码:

    const fetcher = (...args) => fetch(...args).then(res => res.json())
    const  data, error  = useSWR('http://localhost:3000/appi/daily', fetcher)
    if (error) return <div>failed to load</div>
    if (!data) return <div>loading...</div>
    
      
    const[displayNumber] = useState(data.currentInfo.randomString)


    //handler function for changing state variable
    function handleNumChange(event)
        console.log(event.target.value);
        setNumber(event.target.value);
       


    
    return(
      <div>
        <div>
            <Navbar className="navbar"/>
            <h2>data.currentInfo.username</h2>
            <h2>displayNumber</h2>

简而言之,我使用 swr 提取数据,将此信息添加到状态变量,然后使用 h2 显示它。

谁能告诉我这种方法可能有什么问题?

我在网上搜索了错误,说它可能是由 useEffect 挂钩引起的,但我的代码中没有。

【问题讨论】:

将所有钩子移动到组件顶部和条件渲染之前 - reactjs.org/docs/… 嗨,如果我将钩子移到顶部,const[displayNumber] = useState(data.currentInfo.randomString) 上面的代码将不起作用,因为 data.currentInfo 尚未初始化 是的,然后你得到一个错误,我看到了 - 你需要将displayNumber 的初始状态设置为默认值,即useState(data &amp;&amp; data.currentInfo &amp;&amp; data.currentInfo.randomString || null) 您好,先生,我刚刚尝试了您的建议,但仍然收到相同的错误“初始化前无法访问'数据'” 对,完全按照下面答案中的建议进行操作,但在我之前的评论中添加检查。 【参考方案1】:

错误描述了你比以前的渲染有更多的钩子。如果你阅读了 react 文档,所有的 useState 钩子都应该在每次渲染时被调用。你不能有条件useState,而你的代码有一个额外的useState,如下:

if (error) return <div>failed to load</div>
if (!data) return <div>loading...</div> 

这意味着如果没有error 并且只有data 则将调用const[displayNumber] = useState(data.currentInfo.randomString) 行。

编辑: 将其移到顶部通常可以解决您的问题。

    const fetcher = (...args) => fetch(...args).then(res => res.json())
    const  data, error  = useSWR('http://localhost:3000/appi/daily', fetcher)
    //const[displayNumber] = useState(data.currentInfo.randomString) //Needs null checks ofcourse
    //With null checks
    const[displayNumber] = useState((data && data.currentInfo && data.currentInfo.randomString) || undefined)
    //OR
    //const[displayNumber] = useState(data?.currentInfo?.randomString)
    if (error) return <div>failed to load</div>
    if (!data) return <div>loading...</div>

【讨论】:

把它移到顶部,你的意思是把状态钩子移到代码的顶部吗?将其移到数据获取之上会导致构建错误,因为数据尚未初始化。 您好,抱歉刚刚看到您的更新,它说 currentInfo 未定义。我已经在另一个页面上使用相同的方法实现了,如果在 swr 的最后一行之后的行 const[displayNumber] = useState(data.currentInfo.randomString)s 那么它能够获取数据 是的,您需要检查是否所有属性都已定义,您可以使用this。例如:useState(data?.currentInfo?.randomString)或类似useState((data &amp;&amp; data.currentInfo &amp;&amp; data.currentInfo.randomString ) || undefined) 添加到答案中

以上是关于Next.JS“比上一次渲染时渲染了更多的钩子”的主要内容,如果未能解决你的问题,请参考以下文章

Typescript next.js + i18n 的正确 getServerSideProps 语法

如何使用 Next.js 在组件级别导入 SCSS

Next.js 应用在生产环境中频繁重新加载

在 TypeScript 和 Next.js 中使用绝对导入解析模块

如何在 Next.js 中设置 i18n 翻译的 URL 路由?

NextAuth jwt 作为 header.Authorization Bearer Token Next Js