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')
解决方案
问题根源分析
- 初始State类型不匹配:
customer初始值设为数组[],但API返回的是单个对象,数组不存在customerInfo、vehicleInfo这类属性,第一次渲染时直接访问嵌套属性会触发报错。 - useEffect回调逻辑错误:
then方法里的两个setState用逗号分隔,这会导致setIsLoaded在setCustomer之前执行,组件提前进入已加载状态,但此时customer还是初始空数组,从而抛出错误。 - 缺少空值保护:即使修复加载逻辑,网络请求存在延迟,渲染时可能出现
customer未填充的情况,直接访问嵌套属性依然会报错。
修复步骤
- 修正初始State类型:将
customer的初始值改为空对象{},匹配API返回的数据类型。 - 修复useEffect回调写法:把
then里的两个setState包裹在箭头函数中,确保setIsLoaded在setCustomer执行完成后再触发。 - 添加空值保护:使用可选链操作符
?.访问嵌套属性,避免因对象未加载导致的报错;同时优化加载状态判断,结合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
相关产品推荐
相关产品推荐

