You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js SSG页面每次渲染获新props对象,如何避免重复渲染?

问题原因

在Next.js客户端导航场景下(比如通过Link组件切换页面),SSG页面的静态数据会从内置JSON文件中重新解析——即便数组内容完全一致,每次解析都会生成新引用的数组。useMemo依赖判断基于引用相等性(浅比较),因此每次返回Home页面时,allPostsData的引用变化会触发useMemo重新执行,导致打印useMemo log。

解决方法

方法一:用React.memo包裹组件并自定义props比较逻辑

通过React.memo缓存Home组件,自定义比较函数忽略引用变化,只判断数组内容是否一致:

import React from 'react';
// ... 其他导入代码

const Home = ({ allPostsData }) => {
  // ... 组件原有逻辑
}

// 自定义props比较函数,判断帖子数据内容是否一致
const arePropsEqual = (prevProps, nextProps) => {
  const prevData = prevProps.allPostsData;
  const nextData = nextProps.allPostsData;
  
  if (prevData.length !== nextData.length) return false;
  
  return prevData.every((prevItem, index) => {
    const nextItem = nextData[index];
    return prevItem.id === nextItem.id && 
           prevItem.title === nextItem.title && 
           prevItem.date === nextItem.date;
  });
};

export default React.memo(Home, arePropsEqual);

// ... getStaticProps逻辑不变

方法二:抽离列表渲染为独立的memoized组件

把帖子列表的渲染逻辑拆成单独组件,用React.memo包裹,避免父组件重新渲染时影响子组件:

import React from 'react';
// ... 其他导入代码

// 抽离的帖子列表组件,用React.memo包裹
const PostList = React.memo(({ postsData }) => {
  return postsData.map(({ id, date, title }) => (
    <li className={utilStyles.listItem} key={id}>
      {title}
      <br />
      {id}
      <br />
      {date}
    </li>
  ));
});

const Home = ({ allPostsData }) => {
  return (
    <Layout home>
      <ul className={utilStyles.list}>
        <PostList postsData={allPostsData} />
      </ul>
    </Layout>
  )
}

// ... getStaticProps逻辑不变

如果需要更严格的缓存,也可以给PostList添加和方法一一致的自定义比较函数。

方法三:在组件内用useRef缓存数据内容

通过useRef保存上一次的数据和生成的列表,只有当内容变化时才重新渲染:

import { useMemo, useRef } from 'react';
// ... 其他导入代码

const Home = ({ allPostsData }) => {
  const cachedData = useRef({
    data: allPostsData,
    posts: null
  });

  const posts = useMemo(() => {
    // 对比数据内容是否一致
    const isSame = cachedData.current.data.length === allPostsData.length &&
      cachedData.current.data.every((item, index) => {
        const newItem = allPostsData[index];
        return item.id === newItem.id && item.title === newItem.title && item.date === newItem.date;
      });

    if (isSame && cachedData.current.posts) {
      return cachedData.current.posts;
    }

    console.log('useMemo log');
    const newPosts = allPostsData.map(({ id, date, title }) => (
      <li className={utilStyles.listItem} key={id}>
        {title}
        <br />
        {id}
        <br />
        {date}
      </li>
    ));

    // 更新缓存
    cachedData.current = {
      data: allPostsData,
      posts: newPosts
    };

    return newPosts;
  }, [allPostsData]);

  return (
    <Layout home>
      <ul className={utilStyles.list}>
        {posts}
      </ul>
    </Layout>
  )
}

// ... getStaticProps逻辑不变

内容的提问来源于stack exchange,提问作者Dmitrii Ajtyan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 16:18:25