React电商网站出现「两个子元素key重复」报错求助
React购物车组件「Encountered two children with the same key」错误解决
问题描述
开发电商网站的CartScreen组件时,渲染购物车列表触发了「Encountered two children with the same key」错误,核心代码如下:
import React, {useEffect} from 'react' import { Link, useParams, useNavigate, useLocation, useSearchParams } from 'react-router-dom' import { useDispatch, useSelector } from 'react-redux' import { Row, Col, ListGroup, Image, Form, Button, Card} from 'react-bootstrap' import Message from '../components/Message' import { addToCart } from '../actions/cartActions' export default function CartScreen() { const { id} = useParams() const { search } = useLocation(); const [searchParams] = useSearchParams(); const dispatch = useDispatch(); const productID = id; const qty = search ? Number(search.split("=")[1]) : 1; const cart = useSelector(state => state.cart) const { cartItems} = cart console.log('cartItems:', cartItems) useEffect(() => { if(productID) { dispatch(addToCart(productID, qty)) } }, [dispatch, productID, qty]) return ( <Row> <Col md={8}> <h1>Shopping Cart</h1> {cartItems.length === 0 ? ( <Message variant='info'> Your cart is empty <Link to='/'>Go Back</Link> </Message> ) : ( <ListGroup variant='flush'> {cartItems.map(item => ( <ListGroup.Item key= { item.product }> <Row> <Col md={2}> <Image src={item.image} alt={item.name} fluid rounded/> </Col> <Col md={3}> <Link to={`/product/${item.product}`}>{item.name}</Link> </Col> <Col md={2}> ${item.price} </Col> </Row> </ListGroup.Item> ))} </ListGroup> )} </Col> <Col md={4}> </Col> </Row> ) }
错误原因
- 直接触发原因:当前列表项使用
item.product(产品ID)作为key,如果用户多次添加同一商品到购物车,cartItems数组中会出现多个拥有相同product值的条目,导致React渲染列表时检测到重复key。 - 根本原因:
addToCart对应的Redux reducer逻辑存在问题——当添加已有商品时,没有累加数量,而是直接向cartItems中新增了一条相同产品ID的记录。
解决方法
方法一:修改Redux Reducer实现商品数量累加(推荐)
修改购物车reducer中处理CART_ADD_ITEM的逻辑,当添加的商品已存在时,仅更新数量而非新增条目:
// 示例reducer代码片段 const cartReducer = (state = { cartItems: [] }, action) => { switch (action.type) { case 'CART_ADD_ITEM': const newItem = action.payload; const existingItem = state.cartItems.find(item => item.product === newItem.product); if (existingItem) { // 已有商品则更新数量 return { ...state, cartItems: state.cartItems.map(item => item.product === existingItem.product ? { ...item, qty: item.qty + newItem.qty } : item ) } } else { // 无该商品则新增条目 return { ...state, cartItems: [...state.cartItems, newItem] } } // 其他case逻辑... default: return state; } }
修改后cartItems中同一商品只会存在一条记录,item.product作为key就不会重复。
方法二:使用唯一key(仅在需要保留多条同商品记录时使用)
如果业务需要允许购物车中存在多条同一商品的记录(比如不同规格、属性),需要为每条生成唯一key,比如结合产品ID和唯一标识:
// 假设每条购物车条目有唯一id字段 <ListGroup.Item key={item.id}> // 临时用index兜底(不推荐,会影响列表更新性能) <ListGroup.Item key={`${item.product}-${index}`}>
额外小问题修正
代码中ListGroup的属性varient拼写错误,应改为variant,否则组件样式可能无法正常生效。
内容的提问来源于stack exchange,提问作者Erick Cabrera Andrade
相关产品推荐
相关产品推荐

