React电商详情页点击相似产品无法更新内容问题求助
问题详情
开发电商网站时,点击产品可进入DetailPage展示完整详情,页面底部能正常从API获取并展示同类别相似产品,但点击相似产品的Link后,DetailPage页面未更新为该相似产品的内容。
原因分析
核心问题是组件未监听路由参数id的变化:
- React Router在同一个组件的路由参数变化时,不会重新挂载组件,仅更新路由参数
- 现有代码中,用于查找当前产品的
useEffect仅依赖products,未加入id参数,导致路由id变化时,该useEffect不会重新触发,无法更新当前展示的产品数据
解决方案
1. 为产品查找的useEffect添加id依赖
修改第一个useEffect的依赖数组,加入id,确保路由参数变化时重新查找产品:
useEffect(()=>{ // 先判断products是否存在,避免报错 if(!products?.length) return; const product = products.find(product => product.id === Number(id)) if(product){ setItem(product) setMainImg(product.thumbnail) } },[products, id]) // 新增id到依赖数组
2. 优化空值处理(可选但推荐)
在查找产品前先判断products是否存在,避免数组方法调用报错;同时处理找不到对应产品的情况:
useEffect(()=>{ if(!products?.length) { setItem({}); setMainImg(''); return; } const product = products.find(product => product.id === Number(id)) if(product){ setItem(product) setMainImg(product.thumbnail) } else { // 处理找不到产品的情况,比如跳转到404或清空状态 setItem({}); setMainImg(''); } },[products, id])
3. 完整修改后的代码
import React, { useEffect, useState } from 'react' import { useParams, Link } from 'react-router-dom' import useFetch from '../../Component/UseFetch/useFetch' import './detailPage.css' const DetailPage = () => { const [item, setItem] = useState({}) // 初始值改为空对象更合理 const [mainImg, setMainImg] = useState('') const [sameProduct, setSameProduct] = useState([]) const { loading, products } = useFetch('https://dummyjson.com/products') const { id } = useParams() useEffect(()=>{ if(!products?.length) { setItem({}); setMainImg(''); return; } const product = products.find(product => product.id === Number(id)) if(product){ setItem(product) setMainImg(product.thumbnail) } else { setItem({}); setMainImg(''); } },[products, id]) // 关键修改:添加id到依赖数组 useEffect(()=>{ if(!products?.length || !item.category) return; const allProduct = products.filter(product => product.category === item.category) setSameProduct(allProduct) }, [item, products]) return ( loading ? <div style={{ width: '100vw', height: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: '10vw' }}>Loading...</div> : <div> <div> <h1 className='product-headline'>Product Detail</h1> </div> <div className='product-box'> <div> { item?.thumbnail && ( <div style={{height: '320px'}}> <img className='main-image' src={mainImg || item.thumbnail} /> </div> ) } <div className='short-img-box'> { item?.images && item.images.map((image, imgId)=>{ return <img className='short-img' key={imgId} src={image} onClick={()=> setMainImg(image) }/> }) } </div> </div> <div> { item?.price && !isNaN(item.price) && ( <div> <h1>{item.title}</h1> <div> <span>Rating: {item.rating}</span> <span>Available Stock: {item.stock}</span> </div> <div> <span>{parseInt(item.price + item.price / 100 * 25)}</span><br></br> <span>{item.price}</span> </div> <p>{item.description}</p> </div> ) } <button>Add to cart</button> </div> </div> <div> <h1 style={{textAlign: 'center'}}>Review section</h1> </div> <div> <h1 className='product-headline'>Similar Products</h1> <div className='products'> { sameProduct.map((product)=>{ const {id, title, price, thumbnail, rating, stock} = product return ( <div key={id} className='product'> <Link to={`/detailpage/${id}`}><img src={thumbnail} /></Link> <div className='product-details'> <Link className='title' to={`/detailpage/${id}`}><h3>{title}</h3></Link> <div className='price-rating'> <p>${price}</p> <p>Rating: {rating}/5</p> </div> </div> <button className='add-cart'>ADD TO CART</button> <span className='product-stock'>Stock: {stock}</span> </div> ) }) } </div> </div> </div> ) } export default DetailPage
内容的提问来源于stack exchange,提问作者M Hasan
相关产品推荐
相关产品推荐

