React中如何单独管理可配置产品选项状态并实现选中验证?
React可配置产品选项实现方案
需求说明
- 单独管理每个可配置产品选项的状态,保证每个配置项(如颜色、尺寸)仅能选中一个选项;
- 实现选中验证逻辑:
- 未选中任何选项时,提示用户选择颜色和尺寸;
- 仅选中颜色或尺寸其中一项时,提示用户选择未选中的配置项。
可配置产品JSON数据
{ "configurable_options": [ { "__typename": "ConfigurableProductOptions", "id": 167, "attribute_id": "93", "label": "Color", "position": 1, "use_default": false, "attribute_code": "color", "values": [ { "__typename": "ConfigurableProductOptionsValues", "value_index": 50, "label": "Blue", "swatch_data": { "__typename": "ColorSwatchData", "value": "#1857f7" } }, { "__typename": "ConfigurableProductOptionsValues", "value_index": 53, "label": "Green", "swatch_data": { "__typename": "ColorSwatchData", "value": "#53a828" } }, { "__typename": "ConfigurableProductOptionsValues", "value_index": 56, "label": "Orange", "swatch_data": { "__typename": "ColorSwatchData", "value": "#eb6703" } } ], "product_id": 1194 }, { "__typename": "ConfigurableProductOptions", "id": 166, "attribute_id": "144", "label": "Size", "position": 0, "use_default": false, "attribute_code": "size", "values": [ { "__typename": "ConfigurableProductOptionsValues", "value_index": 166, "label": "XS", "swatch_data": { "__typename": "TextSwatchData", "value": "XS" } }, { "__typename": "ConfigurableProductOptionsValues", "value_index": 167, "label": "S", "swatch_data": { "__typename": "TextSwatchData", "value": "S" } }, { "__typename": "ConfigurableProductOptionsValues", "value_index": 168, "label": "M", "swatch_data": { "__typename": "TextSwatchData", "value": "M" } }, { "__typename": "ConfigurableProductOptionsValues", "value_index": 169, "label": "L", "swatch_data": { "__typename": "TextSwatchData", "value": "L" } }, { "__typename": "ConfigurableProductOptionsValues", "value_index": 170, "label": "XL", "swatch_data": { "__typename": "TextSwatchData", "value": "XL" } } ], "product_id": 1194 } ] }
修改后的React实现代码
import { Box, Button, Container, Stack, ToggleButton, ToggleButtonGroup, Typography, Alert, } from "@mui/material"; import { ReactElement, useState } from "react"; import products from "../utils/data.json"; const ProductDetail = (): ReactElement => { // 按属性代码存储各配置项的选中值,初始为空对象 const [selectedOptions, setSelectedOptions] = useState<Record<string, any>>({}); const [cartItems, setCartItems] = useState<Record<string, any>>({}); const [errorMessage, setErrorMessage] = useState<string>(""); // 为每个配置项生成专属的选择事件处理函数 const handleOptionChange = (attributeCode: string) => ( event: React.MouseEvent<HTMLElement>, newOption: any ) => { setErrorMessage(""); setSelectedOptions(prev => ({ ...prev, [attributeCode]: newOption })); }; // 添加到购物车的验证与处理逻辑 const addToCart = () => { const { color, size } = selectedOptions; let message = ""; if (!color && !size) { message = "请选择颜色和尺寸"; } else if (!color) { message = "请选择颜色"; } else if (!size) { message = "请选择尺寸"; } if (message) { setErrorMessage(message); return; } // 验证通过,更新购物车数据 setCartItems(selectedOptions); console.log("已添加到购物车:", selectedOptions); }; return ( <> <Box> <Container maxWidth="sm"> {/* 错误提示区域 */} {errorMessage && ( <Alert severity="error" sx={{ mt: 3 }}> {errorMessage} </Alert> )} {/* 渲染所有可配置选项组 */} {products.configurable_options.map((option) => ( <Stack key={option.id} direction="column" alignItems="flex-start" justifyContent="left" sx={{ mt: 3 }} > <Typography variant="subtitle1" sx={{ mb: 1 }}> {option.label} </Typography> <ToggleButtonGroup color="primary" exclusive aria-label={`选择${option.label}`} onChange={handleOptionChange(option.attribute_code)} value={selectedOptions[option.attribute_code]} > {option.values.map((item) => ( <ToggleButton key={item.value_index} value={item}> {item.label} </ToggleButton> ))} </ToggleButtonGroup> </Stack> ))} <Button variant="contained" sx={{ mt: 5 }} onClick={addToCart}> 添加到购物车 </Button> </Container> </Box> </> ); }; export default ProductDetail;
核心修改点说明
- 状态结构调整:将原单一值状态改为对象结构,通过配置项的
attribute_code作为键,分别存储每个配置项的选中值,确保各配置组独立管理选中状态; - 事件处理优化:通过闭包为每个
ToggleButtonGroup绑定专属处理函数,精准更新对应配置项的选中状态,避免状态混乱; - 验证逻辑实现:在添加到购物车时检查颜色和尺寸的选中状态,根据不同场景生成对应的错误提示,使用MUI的
Alert组件直观展示; - UI体验提升:添加配置项标签,调整布局为纵向堆叠,让选项组的归属更清晰。
内容的提问来源于stack exchange,提问作者Nur Nomad Montreal
相关产品推荐
相关产品推荐

