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

React中如何访问JSON嵌套对象并setState后在JSX中展示?

问题

我正在从REST API地址localhost:3001/customers/id获取JSON对象,尝试将其设置为React组件的state,但在JSX中展示内容时访问嵌套对象遇到困难。

组件代码如下:

import { React, useState, useEffect } from "react";
import { useParams } from "react-router-dom";
import './CustomerItem.css'

const CustomerItem = () => {
    const { id } = useParams()
    const [customer, setCustomer] = useState([])
    const [isLoaded, setIsLoaded] = useState(false)

    useEffect(() => {
        fetch(`http://localhost:3001/customers/${id}`)
        .then((response) => response.json())
        .then((data) =>
            setCustomer(data),
            setIsLoaded(!isLoaded)
        )
    }, [id])

    if (!isLoaded) return <h1>请刷新页面...</h1>
     
    return (
         <div> 
             <h1> {customer.customerInfo.name} </h1>
             <h3> {customer.vehicleInfo.year} {customer.vehicleInfo.make} {customer.vehicleInfo.model} </h3>
         </div>
    )
}
export default CustomerItem

API返回的JSON结构:

{
   "id": 1,
   "customerInfo": {
      "name": "Samara Grant",
      "phone": "347-555-5555",
      "email": "sam@example.com",
      "address": "123 Spring St New York, NY 11001"
   },
   "vehicleInfo": {
      "year": "2018",
      "make": "BMW",
      "model": "M4",
      "mileage": "18,564",
      "vin": "WBS3R9C50FK331665",
      "plateNumber": "M4DEULK"
   },
   "repairOrders": [
      {
         "id": 100,
         "dateOfService": "03/12/2023",
         "customerConcern": "Customer states intermittent whistling sound coming from bonnet. Only after vehicle is warm and @ idle",
         "technicianDiagnosis": "Upon test drive audible whistling noise persists. Located @ PVC Valve in valve cover. Valve cover needs to be replaced",
         "partsOrdered": "Qty: 1x - Part#11127846359 | S55 Valve Cover",
         "serviceAdvisor": "JL",
         "technician": "06"
      },
      {
         "id": 101,
         "dateOfService": "03/29/2023",
         "customerConcern": "Customer states oil leak coming from engine",
         "technicianDiagnosis": "Upon inspection oil leaking from valve cover. Valve cover appears to be unwarped. Gasket will need replacing.",
         "partsOrdered": "Qty: 1x - Part#11127587804 | S55 Valve Cover Gasket Seal",
         "serviceAdvisor": "JL",
         "technician": "06"
      }
   ]
}

当我console.log(data)时可以看到完整的对象及其嵌套信息,但尝试在JSX中用点语法访问嵌套数据时出现以下错误:

TypeError: 无法读取未定义的属性(读取'year')

解决方案

问题根源分析

  1. 初始State类型不匹配:customer初始值设为数组[],但API返回的是单个对象,数组不存在customerInfo、vehicleInfo这类属性,第一次渲染时直接访问嵌套属性会触发报错。
  2. useEffect回调逻辑错误:then方法里的两个setState用逗号分隔,这会导致setIsLoaded在setCustomer之前执行,组件提前进入已加载状态,但此时customer还是初始空数组,从而抛出错误。
  3. 缺少空值保护:即使修复加载逻辑,网络请求存在延迟,渲染时可能出现customer未填充的情况,直接访问嵌套属性依然会报错。

修复步骤

  1. 修正初始State类型:将customer的初始值改为空对象{},匹配API返回的数据类型。
  2. 修复useEffect回调写法:把then里的两个setState包裹在箭头函数中,确保setIsLoaded在setCustomer执行完成后再触发。
  3. 添加空值保护:使用可选链操作符?.访问嵌套属性,避免因对象未加载导致的报错;同时优化加载状态判断,结合customer数据是否存在来判断,更可靠。

修复后的完整代码

import { React, useState, useEffect } from "react";
import { useParams } from "react-router-dom";
import './CustomerItem.css'

const CustomerItem = () => {
    const { id } = useParams()
    // 初始化为空对象,匹配API返回的对象类型
    const [customer, setCustomer] = useState({})
    const [isLoaded, setIsLoaded] = useState(false)

    useEffect(() => {
        fetch(`http://localhost:3001/customers/${id}`)
            .then((response) => response.json())
            .then((data) => {
                // 用箭头函数包裹,确保两个状态更新顺序执行
                setCustomer(data);
                setIsLoaded(true);
            })
            // 添加错误处理,避免请求失败后组件一直卡在加载状态
            .catch(err => {
                console.error('获取客户数据失败:', err);
                setIsLoaded(true);
            })
    }, [id])

    // 结合加载状态和customer数据判断,避免误判已加载
    if (!isLoaded || Object.keys(customer).length === 0) {
        return <h1>加载中...</h1>
    }
     
    return (
         <div> 
             {/* 使用可选链操作符做空值保护,防止嵌套属性未定义 */}
             <h1>{customer.customerInfo?.name}</h1>
             <h3>
                 {customer.vehicleInfo?.year} {customer.vehicleInfo?.make} {customer.vehicleInfo?.model}
             </h3>
         </div>
    )
}
export default CustomerItem

额外优化建议

  • 可以移除isLoaded状态,直接通过customer.id或者Object.keys(customer).length判断数据是否加载完成,减少状态管理的复杂度。
  • 可在错误处理中添加用户可见的错误提示,提升用户体验。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 09:16:14