ItemDetailPage使用axios调用API时出现解构null的TypeError问题
解决React组件中解构null状态导致的TypeError错误
问题描述
实现ItemDetailPage组件时,调用http://localhost:5001/products/${id}接口获取数据,出现错误:TypeError: 无法解构product的'prodImageURL'属性,因为product为null。
错误代码如下:
import React, { useState, useEffect } from "react"; import { useParams } from "react-router-dom"; import axios from "axios"; function ItemDetailPage() { const { id} = useParams(); const [product, setProduct] = useState(null); const { prodImageURL, name, funding, personnel, price } = product; console.log("prodImageURL, name, funding, personnel, price",prodImageURL, name, funding, personnel, price); const imgURL_full = `http://localhost:5001/${prodImageURL}`; console.log("product", product); useEffect(() => { axios.get(`http://localhost:5001/products/${id}`) .then((response) => { setProduct(response.data); }) .catch((error) => { console.error(error); }); }, [id]); if (!product) { return <div>삼품이 없습니다</div>; } return ( <div> <div className='detail-info'> <img src={imgURL_full} alt={name} /> <div className='detail-text'> <p className='detail-title'>{name}</p> <p className='detail-funding'>펀딩 진행중:{funding}</p> <p className='detail-personnel'>펀딩 인원:{personnel}</p> <p>가격: {price}</p> </div> </div> </div> ); } export default ItemDetailPage;
错误原因
组件初始化时product状态被设为null,但你在组件顶层直接对product进行属性解构。React组件的渲染流程是先执行顶层代码,再处理useEffect和条件判断。所以首次渲染时,解构null的属性会直接触发TypeError,后续的if (!product)判断根本来不及执行。
解决方案
核心是确保只在product不为null时才解构其属性,以下是两种常用修复方式:
方式一:将解构移到product存在的判断之后
把属性解构代码放到if (!product)的判断逻辑之后,确保只有当product有值时才执行解构操作:
import React, { useState, useEffect } from "react"; import { useParams } from "react-router-dom"; import axios from "axios"; function ItemDetailPage() { const { id} = useParams(); const [product, setProduct] = useState(null); useEffect(() => { axios.get(`http://localhost:5001/products/${id}`) .then((response) => { setProduct(response.data); }) .catch((error) => { console.error(error); }); }, [id]); if (!product) { return <div>상품이 없습니다</div>; } // 确认product存在后再解构属性 const { prodImageURL, name, funding, personnel, price } = product; const imgURL_full = `http://localhost:5001/${prodImageURL}`; return ( <div> <div className='detail-info'> <img src={imgURL_full} alt={name} /> <div className='detail-text'> <p className='detail-title'>{name}</p> <p className='detail-funding'>펀딩 진행중:{funding}</p> <p className='detail-personnel'>펀딩 인원:{personnel}</p> <p>가격: {price}</p> </div> </div> </div> ); } export default ItemDetailPage;
方式二:使用可选链和默认值进行安全解构
如果需要在顶层保留解构逻辑,可以使用可选链操作符(??)和默认值,避免null解构报错:
import React, { useState, useEffect } from "react"; import { useParams } from "react-router-dom"; import axios from "axios"; function ItemDetailPage() { const { id} = useParams(); const [product, setProduct] = useState(null); // 用?? {}将null转为空对象,再配合默认值避免undefined const { prodImageURL = "", name = "", funding = 0, personnel = 0, price = 0 } = product ?? {}; // 只有product存在时才拼接完整图片地址 const imgURL_full = product ? `http://localhost:5001/${prodImageURL}` : ""; useEffect(() => { axios.get(`http://localhost:5001/products/${id}`) .then((response) => { setProduct(response.data); }) .catch((error) => { console.error(error); }); }, [id]); if (!product) { return <div>상품이 없습니다</div>; } return ( <div> <div className='detail-info'> <img src={imgURL_full} alt={name} /> <div className='detail-text'> <p className='detail-title'>{name}</p> <p className='detail-funding'>펀딩 진행중:{funding}</p> <p className='detail-personnel'>펀딩 인원:{personnel}</p> <p>가격: {price}</p> </div> </div> </div> ); } export default ItemDetailPage;
两种方式中,方式一逻辑更清晰,严格控制了解构时机,避免多余的默认值设置,推荐使用。
内容的提问来源于stack exchange,提问作者조민성
相关产品推荐
相关产品推荐

