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

如何解决Next.js中'use client'导致客户端代码重复执行或无限挂起问题

问题分析与解决方案

现象原因

  • React 18 Strict Mode 触发重复执行:开发环境下,React Strict Mode会刻意重复执行组件渲染、useEffect等逻辑,用来检测潜在的代码问题。添加'use client'后组件转为客户端组件,日志打印和API请求会被Strict Mode触发两次——这是开发环境的预期行为,生产环境不会出现该重复。
  • 客户端组件数据获取逻辑重复触发:未加'use client'时是服务端组件,数据获取仅在服务端执行一次;转为客户端组件后,数据获取逻辑会在客户端渲染时执行,再加上Strict Mode的重复检测,就出现两次客户端请求。拆分文件后服务端仍会执行一次原逻辑,客户端两次,导致总共三次API请求。
  • Server Actions 配置/使用有误:Next.js 13.4.4的实验性Server Actions存在兼容性问题,若直接在组件渲染阶段调用Server Action,会触发无限重渲染导致页面挂起,或者配置未完全生效。

解决方法

  1. 区分开发与生产环境行为

    • 开发环境的两次执行是Strict Mode的正常检测机制,生产环境React会自动合并重复执行的逻辑,API请求只会触发一次。若需临时在开发环境避免,可在next.config.js中关闭Strict Mode(不推荐长期使用,会失去问题检测能力):
      module.exports = {
        reactStrictMode: false,
      }
      
  2. 优化客户端数据获取逻辑

    • 使用数据缓存库(如useSWR或react-query),它们会自动处理重复请求、缓存响应结果:
      'use client';
      import useSWR from 'swr';
      
      const fetcher = (url) => fetch(url).then(res => res.json());
      
      export default function ClientComponent() {
        const { data } = useSWR('/api/data', fetcher);
        // 渲染逻辑
      }
      
    • 采用服务端组件+客户端组件的组合:页面作为服务端组件,在服务端完成数据获取,再将数据通过props传递给使用Chakra UI的客户端组件,彻底避免客户端重复请求:
      // 服务端页面组件
      import ClientComponent from './ClientComponent';
      
      async function getData() {
        const res = await fetch('https://api.example.com/data');
        return res.json();
      }
      
      export default async function Page() {
        const data = await getData();
        return <ClientComponent data={data} />;
      }
      
      // 客户端组件(使用Chakra UI)
      'use client';
      import { Box } from '@chakra-ui/react';
      
      export default function ClientComponent({ data }) {
        return <Box>{data.content}</Box>;
      }
      
  3. 正确使用Server Actions

    • 确保next.config.js配置正确:
      module.exports = {
        experimental: {
          serverActions: true,
        },
      }
      
    • Server Action函数需单独导出,且在客户端组件中通过startTransition或表单提交调用,避免在渲染阶段直接执行导致无限循环:
      // 单独的server action文件
      'use server';
      export async function getData() {
        const res = await fetch('https://api.example.com/data');
        return res.json();
      }
      
      // 客户端组件
      'use client';
      import { useState, startTransition } from 'react';
      import { getData } from './actions';
      
      export default function ClientComponent() {
        const [data, setData] = useState(null);
      
        const fetchData = () => {
          startTransition(async () => {
            const result = await getData();
            setData(result);
          });
        };
      
        return (
          <button onClick={fetchData}>获取数据</button>
        );
      }
      

内容的提问来源于stack exchange,提问作者Gabriel Izoton

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 15:38:36