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

使用useEffect获取Sanity hero数据时渲染报错:无法读取undefined属性

问题分析与解决方法

核心问题

你遇到的报错,本质是两个原因叠加:

  1. 初始状态hero是空数组[],但你试图直接访问数组的heading/tag属性——数组本身没有这些属性,只有数组里的对象才有。
  2. API数据返回前,hero是空数组,即便你改成访问数组元素hero[0].heading,此时hero[0]是undefined,直接访问属性依然会报错。

解决方法

根据你的需求(单个Hero数据还是多个),有两种方案可选:

方案1:查询单个Hero对象(推荐,如果你只有一个Hero条目)

直接修改Sanity查询,取第一个Hero对象而非数组,同时调整初始状态:

import { useState, useEffect } from 'react';
// 假设client已引入

const HeroComponent = () => {
  // 初始状态设为null,明确表示数据未加载
  const [hero, setHero] = useState(null);

  useEffect(() => {
    // 使用async/await的正确写法:在useEffect内部定义async函数
    const fetchHeroData = async () => {
      try {
        const data = await client.fetch(
          `*[_type == "hero"][0]{
            background{
              asset->{
                _id,
                url
              }
            },  
            tag,
            heading,
            subheading 
          }`
        );
        setHero(data);
      } catch (err) {
        console.error('获取Hero数据失败:', err);
      }
    };

    fetchHeroData();
  }, []);

  // 渲染前判断数据是否存在
  return (
    <div className="hero-container">
      {hero ? (
        <>
          <span className="hero-tag">{hero.tag}</span>
          <h1 className="hero-heading">{hero.heading}</h1>
          <p className="hero-subheading">{hero.subheading}</p>
          {/* 用可选链?.防止深层属性访问报错 */}
          {hero.background?.asset?.url && (
            <img src={hero.background.asset.url} alt="Hero背景图" className="hero-bg" />
          )}
        </>
      ) : (
        <p>加载中...</p>
      )}
    </div>
  );
};

export default HeroComponent;

方案2:保留数组查询(如果你有多个Hero条目)

如果需要渲染多个Hero,保持数组查询,渲染时遍历数组并处理空状态:

import { useState, useEffect } from 'react';

const HeroList = () => {
  const [heroes, setHeroes] = useState([]);

  useEffect(() => {
    client
      .fetch(
        `*[_type == "hero"]{
          _id,
          background{
            asset->{
              _id,
              url
            }
          },  
          tag,
          heading,
          subheading 
        }`
      )
      .then(setHeroes)
      .catch(err => console.error('获取Hero列表失败:', err));
  }, []);

  return (
    <div className="hero-list">
      {heroes.length === 0 ? (
        <p>加载中...</p>
      ) : (
        heroes.map(hero => (
          <div key={hero._id} className="hero-item">
            <span>{hero.tag}</span>
            <h2>{hero.heading}</h2>
            <p>{hero.subheading}</p>
            {hero.background?.asset?.url && <img src={hero.background.asset.url} alt="Hero背景" />}
          </div>
        ))
      )}
    </div>
  );
};

export default HeroList;

关键注意点

  • 状态类型匹配:Sanity的*[_type == "hero"]返回数组,*[_type == "hero"][0]返回单个对象,对应调整useState的初始值(数组/null)。
  • 空状态处理:必须在渲染前判断数据是否存在,避免访问undefined的属性。
  • 可选链操作符?.:用于深层属性访问(比如hero.background?.asset?.url),即使中间某个属性不存在,也不会抛出错误。

内容的提问来源于stack exchange,提问作者Abdirahman Mohamed

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 11:01:08