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

React中使用useRef获取商品选项时仅返回第二个商品数据的问题

问题:多个商品卡片共用useRef导致获取数据错误

我做了两个商品卡片,每个都包含颜色、尺寸等分类选项以及「加入购物车」按钮,用React的useRef Hook获取用户选择的分类信息,点击按钮时在控制台打印数据,但无论点击哪个按钮,都仅能获取到第二个商品的选中分类数据。代码如下:

import "./Card.css";
import { useRef } from "react";

function Card() {
  const colorRef = useRef();
  const quantityRef = useRef();
  const sizeRef = useRef();

  const submitHandler = (event) => {
    event.preventDefault();

    const selectedColor = colorRef.current.value;
    const selectedQuantity = quantityRef.current.value;
    const selectedSize = sizeRef.current.value;

    const selectedData = {
      color: selectedColor,
      quantity: selectedQuantity,
      size: selectedSize
    };
    console.log(selectedData);
  };

  return (
    <div className="main-container">
      <div className="container">
        <div className="image-container">
          <img
            src="https://images.pexels.com/photos/9558601/pexels-photo-9558601.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1"
            alt=""
          />
        </div>
        <h2> T-Shirt </h2>
      </div>
      <form className="form-conatiner" onSubmit={submitHandler}>
        <div className="selectors">
          <p>Solid Round Neck T-shirt</p>
          <select id="color" ref={colorRef} name="color" required>
            <option>Color</option>
            <option value="black">Black</option>
            <option value="green">Green</option>
            <option value="orange">Orange</option>
          </select>

          <select ref={quantityRef} name="qantity" required>
            <option>Quantity</option>
            <option value="1">1</option>
            <option value="2">2</option>
            <option value="3">3</option>
          </select>

          <select ref={sizeRef} name="size" required>
            <option>Size</option>
            <option value="medium">Medium</option>
            <option value="large">Large</option>
            <option value="small">Small</option>
          </select>
          <div>
            <button>Add to Cart</button>
          </div>
        </div>
      </form>
      <div className="container">
        <div className="image-container">
          <img
            src="https://images.pexels.com/photos/440320/pexels-photo-440320.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1"
            alt=""
          />
        </div>
        <h2> i-Watch </h2>
      </div>
      <div className="form-conatiner">
        <div className="selectors">
          <p>Dizo watch with amlod </p>
          <select id="2" ref={colorRef} name="color" required>
            <option>Brand</option>
            <option value="Apple">Apple</option>
            <option value="Samsung">Samsung</option>
            <option value="Pixel">Pixel</option>
          </select>

          <select ref={quantityRef} name="qantity" required>
            <option>Quantity</option>
            <option value="1">1</option>
            <option value="2">2</option>
            <option value="3">3</option>
          </select>

          <select ref={sizeRef} name="size" required>
            <option>size </option>
            <option value="29mm">29mm</option>
            <option value="34mm">34mm</option>
            <option value="42mm">42mm</option>
          </select>
          <div>
            <button onClick={submitHandler}>Add to Cart</button>
          </div>
        </div>
      </div>
    </div>
  );
}
export default Card;

问题原因

你把同一个colorRef、quantityRef、sizeRef绑定到了两组不同的选择框上,React中当一个ref被多次赋值给不同DOM元素时,最后绑定的元素会覆盖之前的,所以不管点击哪个按钮,ref.current指向的都是第二个商品的选择框,自然只能拿到第二个商品的数据。

解决方案

把单个商品卡片拆成独立的组件,让每个商品组件自己维护自己的ref和提交逻辑,这样每个组件的ref都是独立的,不会互相干扰。

修改后的代码

import "./Card.css";
import { useRef } from "react";

// 独立的商品卡片组件
function ProductCard({ title, desc, imageSrc, options }) {
  const colorRef = useRef();
  const quantityRef = useRef();
  const sizeRef = useRef();

  const submitHandler = (event) => {
    event.preventDefault();

    const selectedColor = colorRef.current.value;
    const selectedQuantity = quantityRef.current.value;
    const selectedSize = sizeRef.current.value;

    const selectedData = {
      product: title,
      color: selectedColor,
      quantity: selectedQuantity,
      size: selectedSize
    };
    console.log(selectedData);
  };

  return (
    <div>
      <div className="container">
        <div className="image-container">
          <img src={imageSrc} alt={title} />
        </div>
        <h2>{title}</h2>
      </div>
      <form className="form-conatiner" onSubmit={submitHandler}>
        <div className="selectors">
          <p>{desc}</p>
          <select ref={colorRef} name="color" required>
            {options.colorOptions.map(opt => (
              <option key={opt.value} value={opt.value}>{opt.label}</option>
            ))}
          </select>

          <select ref={quantityRef} name="quantity" required>
            {options.quantityOptions.map(opt => (
              <option key={opt.value} value={opt.value}>{opt.label}</option>
            ))}
          </select>

          <select ref={sizeRef} name="size" required>
            {options.sizeOptions.map(opt => (
              <option key={opt.value} value={opt.value}>{opt.label}</option>
            ))}
          </select>
          <div>
            <button>Add to Cart</button>
          </div>
        </div>
      </form>
    </div>
  );
}

function Card() {
  // 定义每个商品的配置
  const tshirtOptions = {
    colorOptions: [
      { label: "Color", value: "" },
      { label: "Black", value: "black" },
      { label: "Green", value: "green" },
      { label: "Orange", value: "orange" }
    ],
    quantityOptions: [
      { label: "Quantity", value: "" },
      { label: "1", value: "1" },
      { label: "2", value: "2" },
      { label: "3", value: "3" }
    ],
    sizeOptions: [
      { label: "Size", value: "" },
      { label: "Medium", value: "medium" },
      { label: "Large", value: "large" },
      { label: "Small", value: "small" }
    ]
  };

  const watchOptions = {
    colorOptions: [
      { label: "Brand", value: "" },
      { label: "Apple", value: "Apple" },
      { label: "Samsung", value: "Samsung" },
      { label: "Pixel", value: "Pixel" }
    ],
    quantityOptions: [
      { label: "Quantity", value: "" },
      { label: "1", value: "1" },
      { label: "2", value: "2" },
      { label: "3", value: "3" }
    ],
    sizeOptions: [
      { label: "size", value: "" },
      { label: "29mm", value: "29mm" },
      { label: "34mm", value: "34mm" },
      { label: "42mm", value: "42mm" }
    ]
  };

  return (
    <div className="main-container">
      <ProductCard
        title="T-Shirt"
        desc="Solid Round Neck T-shirt"
        imageSrc="https://images.pexels.com/photos/9558601/pexels-photo-9558601.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1"
        options={tshirtOptions}
      />
      <ProductCard
        title="i-Watch"
        desc="Dizo watch with amlod"
        imageSrc="https://images.pexels.com/photos/440320/pexels-photo-440320.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1"
        options={watchOptions}
      />
    </div>
  );
}

export default Card;

额外说明

  • 组件化之后,每个商品卡片的状态和ref都是独立的,不会再出现覆盖问题
  • 把商品配置抽成参数,后续新增商品只需要添加对应的配置对象,复用同一个组件即可,维护性更强

内容的提问来源于stack exchange,提问作者Anandhu A

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 13:50:23