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
相关产品推荐
相关产品推荐

