You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 02:35:21