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

React页面刷新报错:TypeError: 无法读取undefined的categoryName属性

问题:React组件刷新时访问嵌套属性报错TypeError

我写了一个ProductDetail组件,通过Axios封装的ProductService获取产品详情。但只要用到product.category.categoryName,页面刷新就会抛出TypeError: Cannot read properties of undefined (reading 'categoryName')错误。

ProductDetail组件代码

import React, { useState, useEffect } from 'react'
import { useParams } from 'react-router'
import { Button, Card, Image } from 'semantic-ui-react'
import ProductService from '../services/productService'

export default function ProductDetail() {
  const { id } = useParams()

  const [product, setProduct] = useState({});

  useEffect(() => {
    let productService = new ProductService();
    productService.getProductById(id).then(result => setProduct(result.data.data))
  }, [])
  return (
    <div>
      <Card.Group>
        <Card fluid>
          <Card.Content>
            <Image
              size='medium'
              src='https://react.semantic-ui.com/images/avatar/large/steve.jpg'
            />
            <Card.Header style={{ marginTop: '0.5em' }}>{product.productName}</Card.Header>
            <Card.Meta></Card.Meta>
            <Card.Description>Units in Stock :
              {product.unitsInStock}
            </Card.Description>
            <Card.Description>Unit Price :
              {product.unitPrice}$
            </Card.Description>
            <Card.Description>
              {product.category.categoryName}
            </Card.Description>
          </Card.Content>
          <Card.Content extra>
            <div className='ui two buttons'>
              <Button basic color='green'>
                Add to Cart
              </Button>
              <Button basic color='red'>
                Add to Favorites
              </Button>
            </div>
          </Card.Content>
        </Card>

      </Card.Group>
    </div>
  )
}

ProductService类代码

import axios from "axios";

export default class ProductService{

    getProducts(){
        return axios.get("http://localhost:8080/api/products/getAll")
    }

    getProductById(productId){
        return axios.get(`http://localhost:8080/api/products/getByProductId?productId=${productId}`)
    }

}

错误信息

API返回的产品对象包含category字段,但错误发生在ProductDetail.jsx第32行,具体错误栈如下:

ProductDetail.jsx:32 Uncaught TypeError: Cannot read properties of undefined (reading 'categoryName')
    at ProductDetail (ProductDetail.jsx:32:1)
    at renderWithHooks (react-dom.development.js:16305:1)
    at mountIndeterminateComponent (react-dom.development.js:20074:1)
    at beginWork (react-dom.development.js:21587:1)
    at HTMLUnknownElement.callCallback (react-dom.development.js:4164:1)
    at Object.invokeGuardedCallbackDev (react-dom.development.js:4213:1)
    at invokeGuardedCallback (react-dom.development.js:4277:1)
    at beginWork$1 (react-dom.development.js:27451:1)
    at performUnitOfWork (react-dom.development.js:26557:1)
    at workLoopSync (react-dom.development.js:26466:1)
ProductDetail @ ProductDetail.jsx:32
renderWithHooks @ react-dom.development.js:16305
mountIndeterminateComponent @ react-dom.development.js:20074
beginWork @ react-dom.development.js:21587
callCallback @ react-dom.development.js:4164
invokeGuardedCallbackDev @ react-dom.development.js:4213
invokeGuardedCallback @ react-dom.development.js:4277
beginWork$1 @ react-dom.development.js:27451
performUnitOfWork @ react-dom.development.js:26557
workLoopSync @ react-dom.development.js:26466
renderRootSync @ react-dom.development.js:26434
performConcurrentWorkOnRoot @ react-dom.development.js:25738
workLoop @ scheduler.development.js:266
flushWork @ scheduler.development.js:239
performWorkUntilDeadline @ scheduler.development.js:533
ProductDetail.jsx:32 Uncaught TypeError: Cannot read properties of undefined (reading 'categoryName')
    at ProductDetail (ProductDetail.jsx:32:1)
    at renderWithHooks (react-dom.development.js:16305:1)
    at mountIndeterminateComponent (react-dom.development.js:20074:1)
    at beginWork (react-dom.development.js:21587:1)
    at HTMLUnknownElement.callCallback (react-dom.development.js:4164:1)
    at Object.invokeGuardedCallbackDev (react-dom.development.js:4213:1)
    at invokeGuardedCallback (react-dom.development.js:4277:1)
    at beginWork$1 (react-dom.development.js:27451:1)
    at performUnitOfWork (react-dom.development.js:26557:1)
    at workLoopSync (react-dom.development.js:26466:1)
ProductDetail @ ProductDetail.jsx:32
renderWithHooks @ react-dom.development.js:16305
mountIndeterminateComponent @ react-dom.development.js:20074
beginWork @ react-dom.development.js:21587
callCallback @ react-dom.development.js:4164
invokeGuardedCallbackDev @ react-dom.development.js:4213
invokeGuardedCallback @ react-dom.development.js:4277
beginWork$1 @ react-dom.development.js:27451
performUnitOfWork @ react-dom.development.js:26557
workLoopSync @ react-dom.development.js:26466
renderRootSync @ react-dom.development.js:26434
recoverFromConcurrentError @ react-dom.development.js:25850
performConcurrentWorkOnRoot @ react-dom.development.js:25750
workLoop @ scheduler.development.js:266
flushWork @ scheduler.development.js:239
performWorkUntilDeadline @ scheduler.development.js:533
react-dom.development.js:18687 The above error occurred in the <ProductDetail> component:

    at ProductDetail (http://localhost:3000/static/js/bundle.js:1033:62)
    at Routes (http://localhost:3000/static/js/bundle.js:46558:5)
    at div
    at GridColumn (http://localhost:3000/static/js/bundle.js:51973:24)
    at div
    at GridRow (http://localhost:3000/static/js/bundle.js:52083:24)
    at div
    at Grid (http://localhost:3000/static/js/bundle.js:51857:22)
    at div
    at Dashboard
    at div
    at Container (http://localhost:3000/static/js/bundle.js:53978:24)
    at div
    at App
    at Router (http://localhost:3000/static/js/bundle.js:46491:15)
    at BrowserRouter (http://localhost:3000/static/js/bundle.js:45300:5)

Consider adding an error boundary to your tree to customize error handling behavior.
Visit https://reactjs.org/link/error-boundaries to learn more about error boundaries.
logCapturedError @ react-dom.development.js:18687
update.callback @ react-dom.development.js:18720
callCallback @ react-dom.development.js:13923
commitUpdateQueue @ react-dom.development.js:13944
commitLayoutEffectOnFiber @ react-dom.development.js:23391
commitLayoutMountEffects_complete @ react-dom.development.js:24688
commitLayoutEffects_begin @ react-dom.development.js:24674
commitLayoutEffects @ react-dom.development.js:24612
commitRootImpl @ react-dom.development.js:26823
commitRoot @ react-dom.development.js:26682
finishConcurrentRender @ react-dom.development.js:25892
performConcurrentWorkOnRoot @ react-dom.development.js:25809
workLoop @ scheduler.development.js:266
flushWork @ scheduler.development.js:239
performWorkUntilDeadline @ scheduler.development.js:533
ProductDetail.jsx:32 Uncaught TypeError: Cannot read properties of undefined (reading 'categoryName')
    at ProductDetail (ProductDetail.jsx:32:1)
    at renderWithHooks (react-dom.development.js:16305:1)
    at mountIndeterminateComponent (react-dom.development.js:20074:1)
    at beginWork (react-dom.development.js:21587:1)
    at beginWork$1 (react-dom.development.js:27426:1)
    at performUnitOfWork (react-dom.development.js:26557:1)
    at workLoopSync (react-dom.development.js:26466:1)
    at renderRootSync (react-dom.development.js:26434:1)
    at recoverFromConcurrentError (react-dom.development.js:25850:1)
    at performConcurrentWorkOnRoot (react-dom.development.js:25750:1)

解决方案

原因分析

页面刷新时,组件先执行初始渲染,此时product是初始值{},product.category为undefined,直接访问product.category.categoryName会触发报错。虽然API请求完成后会更新state,但初始渲染阶段的错误已经导致后续更新无法正常执行。

解决方法

有几种简单的方式可以避免这个问题:

  1. 可选链操作符(推荐)
    在访问嵌套属性时使用?.,当某个属性为undefined或null时会直接返回undefined,不会抛出错误:

    <Card.Description>
      {product.category?.categoryName}
    </Card.Description>
    
  2. 条件渲染
    先判断product.category是否存在,再渲染对应的内容:

    <Card.Description>
      {product.category && product.category.categoryName}
    </Card.Description>
    
  3. 设置初始state的默认结构
    给product的初始值设置与API返回一致的结构,确保category是一个空对象:

    const [product, setProduct] = useState({ category: {} });
    
  4. 加载状态判断
    在API请求完成前显示加载提示,避免渲染未准备好的数据:

    const [product, setProduct] = useState(null);
    
    useEffect(() => {
      let productService = new ProductService();
      productService.getProductById(id).then(result => setProduct(result.data.data))
    }, [])
    
    if (!product) {
      return <div>加载中...</div>;
    }
    
    return (
      // 原渲染内容
    )
    

内容的提问来源于stack exchange,提问作者Burak Koc

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 17:39:54