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

Next.js13异步组件中使用useState实现产品图片预览的问题求助

Next.js 13 异步组件中实现产品图片预览的解决方案

问题根源

Next.js 13 App Router 中,带 async/await 的服务器组件无法使用 React Hooks;即使加了 "use client" 标记,直接在异步组件内混用 await 和 Hooks 也不符合最佳实践,容易引发渲染逻辑冲突。

方案1:拆分组件(推荐)

将数据获取和交互逻辑分离:用异步服务器组件负责获取 Sanity 数据,把图片预览的交互部分抽成独立的客户端组件(可正常使用 useState)。

1. 改造主组件(负责数据获取)

import { getProduct } from '@/sanity/sanity-utils';
import ProductImageGallery from './ProductImageGallery';

export default async function ProductDetails({ params }) {
  const slug = params.product;
  const product = await getProduct(slug);

  return (
    <div>
      <div className='product-detail-container'>
        <ProductImageGallery images={product.image} />
        {/* 其他产品详情内容(如价格、描述等) */}
      </div>
    </div>
  );
}

2. 创建客户端交互组件

新建 ProductImageGallery.jsx 文件:

"use client";
import React, { useState } from 'react';

export default function ProductImageGallery({ images }) {
  // 初始化默认选中第一张图
  const [activeIndex, setActiveIndex] = useState(0);

  return (
    <div>
      <div className='image-container'>
        <img 
          src={images[activeIndex]} 
          alt="product-image"
          className='product-detail-image'
        />
      </div>
      <div className='small-images-container'>
        {images.map((item, i) => (
          <img
            src={item}
            alt={`product-image-${i}`}
            key={i}
            onMouseEnter={() => setActiveIndex(i)}
            // 可选:给当前选中的小图加高亮样式
            className={i === activeIndex ? 'small-image active' : 'small-image'}
          />
        ))}
      </div>
    </div>
  );
}

方案2:客户端组件内用 use Hook 处理异步数据

如果不想拆分组件,可以在客户端组件中使用 Next.js 13 提供的 use Hook 处理异步数据,避免直接在组件顶层用 await。

"use client";
import { getProduct } from '@/sanity/sanity-utils';
import React, { useState, use } from 'react';
import { AiOutlineMinus,AiOutlinePlus,AiFillStar,AiOutlineStar} from 'react-icons/ai';

export default function ProductDetails({ params }) {
  const slug = params.product;
  // 用 use Hook 处理异步数据请求
  const product = use(getProduct(slug));
  const [activeIndex, setActiveIndex] = useState(0);

  return (
    <div>
      <div className='product-detail-container'>
        <div>
          <div className='image-container'>
            <img 
              src={product.image[activeIndex]} 
              alt="product-image"
              className='product-detail-image'
            />
          </div>
          <div className='small-images-container'>
            {product.image.map((item, i) => (
              <img
                src={item}
                alt={`product-image-${i}`}
                key={i}
                onMouseEnter={() => setActiveIndex(i)}
              />
            ))}
          </div>
        </div>
        {/* 其他产品详情内容 */}
      </div>
    </div>
  );
}

关于 Sanity 数据获取的说明

无需调整现有 Sanity 数据获取逻辑,getProduct 函数的实现是正常的,问题仅出在 Next.js 13 的组件渲染规则上,上述两种方案均可完美解决图片预览的交互需求。

内容的提问来源于stack exchange,提问作者Martin Sosa

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 03:07:20