How to Fix: next/image ‘use client’ 报错

2 min read

next/image 配合 ‘use client’ 报错,通常不是图片组件本身坏了,而是 Server Component 与 Client Component 的边界导入方式App Router 使用方式 出了问题。这个问题在 Next.js 13/14 的项目里非常常见,尤其是在把页面或组件改成客户端组件之后,错误会立刻暴露出来。

Understanding the Root Cause

在 Next.js 的 App Router 中,文件默认是 Server Component。当你在文件顶部加上 ‘use client’ 后,这个文件以及它直接依赖的渲染逻辑会进入 Client Component 语义。

这时,next/image 本身通常依然可以使用,但以下几类问题会被放大:

  • 错误的导入方式:必须使用 import Image from 'next/image',如果混用了原生图片逻辑、错误别名、旧写法,容易报错。
  • 向 Client Component 传入不可序列化数据:例如把服务端函数、复杂对象、动态模块结果直接传给使用 Image 的客户端组件,会在渲染阶段报错。
  • 图片 src 不合法:在客户端组件中,如果 srcundefined、空字符串,或者外链域名未在 next.config.js 中配置,也会触发异常。
  • App Router 与旧示例混用:很多历史文章基于 Pages Router,复制到 App Router 并加上 ‘use client’ 后,组件边界和数据流已经变了。
  • 把只能在服务端运行的逻辑塞进客户端组件:比如直接在同一个组件里使用服务端数据获取模式、Node API、服务端依赖,再顺手渲染 next/image,最终看起来像是 Image 报错,实际上根因不是它。

简单说,‘use client’ 不是让 next/image 失效,而是要求这个组件文件必须满足 客户端渲染约束。一旦你的图片来源、组件导入、配置或数据传递方式不符合要求,就会报错。

Step-by-Step Solution

按照下面顺序排查,通常可以快速解决问题。

1. 确认正确导入 next/image

import Image from 'next/image'

不要写错包名,也不要从其他封装层误导入。

2. 确认客户端组件声明位置正确

‘use client’ 必须位于文件第一行,且在任何 import 之前。

'use client'

import Image from 'next/image'

export default function Demo() {
  return (
    <Image
      src="/logo.png"
      alt="logo"
      width={120}
      height={40}
    />
  )
}

如果不是第一行,Next.js 不会把它识别为合法的客户端组件。

3. 优先使用本地静态图片验证问题

先不要直接用远程地址,先用 public 目录下的文件做最小化验证。

// public/images/avatar.png

'use client'

import Image from 'next/image'

export default function Profile() {
  return (
    <Image
      src="/images/avatar.png"
      alt="avatar"
      width={160}
      height={160}
    />
  )
}

如果本地图片正常,说明问题大概率出在 远程图片配置src 数据来源

4. 如果使用远程图片,配置 next.config.js

远程图片域名必须显式允许,否则 next/image 会报错。

/** @type {import('next').NextConfig} */
const nextConfig = {
  images: {
    remotePatterns: [
      {
        protocol: 'https',
        hostname: 'example.com'
      }
    ]
  }
}

module.exports = nextConfig

修改后重启开发服务器。

npm run dev

5. 确保 src 在客户端渲染时一定有值

很多报错来自异步数据未返回时,src 已经参与渲染。

'use client'

import Image from 'next/image'

export default function UserCard({ avatar }) {
  if (!avatar) {
    return <p>Loading...</p>
  }

  return (
    <Image
      src={avatar}
      alt="user avatar"
      width={80}
      height={80}
    />
  )
}

如果你拿到的是接口数据,务必先判断字段是否存在。

6. 不要把服务端专属逻辑直接放进 use client 文件

推荐把数据获取放在 Server Component,再把纯展示组件拆成 Client Component

// app/page.jsx
import ClientImageView from './ClientImageView'

export default async function Page() {
  const data = {
    src: '/images/avatar.png'
  }

  return <ClientImageView src={data.src} />
}
// app/ClientImageView.jsx
'use client'

import Image from 'next/image'

export default function ClientImageView({ src }) {
  return <Image src={src} alt="avatar" width={120} height={120} />
}

这能有效避免 组件边界混乱 导致的问题。

7. 检查是否误用了旧版属性

一些旧项目会使用不兼容的历史写法。请核对当前 Next.js 版本文档,确保没有混用过时 API。

// 推荐使用明确的尺寸
<Image src="/banner.png" alt="banner" width={800} height={400} />

8. 最小可用修复示例

如果你想快速验证环境是否正常,可以直接使用下面这个版本:

'use client'

import Image from 'next/image'

export default function TestImage() {
  return (
    <div>
      <h1>Image Test</h1>
      <Image
        src="/images/test.png"
        alt="test image"
        width={200}
        height={120}
        priority
      />
    </div>
  )
}

如果这个版本可运行,而你原来的版本报错,那么问题几乎可以确定在 远程地址动态数据组件边界 上。

Common Edge Cases

  • 外链图片未配置白名单:这是最常见情况之一,尤其是头像 CDN、对象存储、第三方图床。
  • src 是对象不是字符串:例如接口返回整个文件对象,你却直接传给了 Image
  • public 路径写错:正确写法是 /images/a.png,不是 ./public/images/a.png
  • ‘use client’ 不在文件首行:哪怕前面多一个空导入或注释格式异常,都可能影响识别。
  • 父组件是服务端,子组件要求客户端交互:这本身没问题,但传参必须是 可序列化 的基础数据。
  • 升级 Next.js 后旧代码失效:历史项目中对 next/image 的旧配置、旧属性、旧布局写法可能已不推荐。
  • 本地能跑,部署报错:生产环境域名、图片地址、CDN 主机名与本地不同,需要重新配置 remotePatterns

FAQ

1. 加了 ‘use client’ 以后,next/image 还能用吗?

可以。next/image 支持在客户端组件中使用。报错通常来自 src 无效远程域名未配置导入错误服务端/客户端边界问题

2. 为什么去掉 ‘use client’ 后感觉就不报错了?

因为去掉后文件回到 Server Component 语义,某些客户端阶段才暴露的问题暂时被隐藏了。但如果组件确实需要事件、状态、浏览器 API,还是应该保留 ‘use client’,并按正确方式拆分逻辑。

3. 我用的是网络图片,配置了域名还是报错怎么办?

继续检查 协议子域名端口图片真实地址 是否与配置完全一致,并确认修改 next.config.js 后已经重启服务。如果是动态返回地址,还要确认渲染时不是空值。

如果你正在处理这个 GitHub issue,最稳妥的修复路线是:先用 public 目录本地图片验证 next/image 本身可用,再逐步恢复 ‘use client’、远程地址、动态数据和父子组件传参。这样可以最快定位真正的故障点,而不是误以为问题只出在 next/image 上。

需要进一步核对官方行为变化时,可以参考 Next.js Image 官方文档Client Components 官方说明

Leave a Reply

Your email address will not be published. Required fields are marked *