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

React实现Nike式商品属性单选功能遇useRef取值异常求助

嘿,我来帮你排查这个问题~

你遇到的核心问题是单个useRef无法同时绑定多个循环生成的元素:当你在map循环里把同一个ref绑定到所有radio输入框时,React最终会让这个ref的current指向最后一个被渲染的元素,所以不管你点哪个选项,拿到的都是最后一个radio的值(也就是你说的"M")。

另外还有个小问题:你现在手动操作DOM的classList来切换样式,这其实不符合React的声明式编程思路,更推荐用状态来控制样式变化。

给你两个更合理的解决方案,选哪个都可以:

方案1:用React状态管理选中状态(推荐)

直接用useState来跟踪选中的尺寸,通过状态动态控制样式和radio的选中状态,完全不需要useRef:

import { useState } from 'react';

// 首先定义状态管理选中的尺寸
const [selectedSize, setSelectedSize] = useState('');

// 渲染部分修改成这样
<h1 className="text-center text-2xl">{product.name}</h1>
<div>
  <div className={'block my-3'}>
    {product.attribute?.map((item, index) => (
      <div className={'inline-block'} key={index}>
        <label 
          className={`cursor-pointer py-2 px-3 my-3 mx-2 border h-3 rounded hover:border-black ${
            selectedSize === item.value ? 'border-black' : 'border-grey-500'
          }`} 
          htmlFor={item.id}
        >
          {item.value}
        </label>
        <input 
          className="hidden" 
          type="radio" 
          id={item.id} 
          value={item.value} 
          name={'selectSize'}
          // 用状态控制radio是否选中
          checked={selectedSize === item.value}
          //  onChange事件直接更新状态
          onChange={(e) => setSelectedSize(e.target.value)}
        />
      </div>
    ))}
  </div>
</div>

方案2:如果想保留label的点击事件

也可以在循环渲染时,直接把当前选项的value传给点击事件,同样不需要ref:

import { useState } from 'react';

const [selectedSize, setSelectedSize] = useState('');

const labelOnclickHandler = (value) => {
  setSelectedSize(value);
};

// 渲染部分
<h1 className="text-center text-2xl">{product.name}</h1>
<div>
  <div className={'block my-3'}>
    {product.attribute?.map((item, index) => (
      <div className={'inline-block'} key={index}>
        <label 
          onClick={() => labelOnclickHandler(item.value)}
          className={`cursor-pointer py-2 px-3 my-3 mx-2 border h-3 rounded hover:border-black ${
            selectedSize === item.value ? 'border-black' : 'border-grey-500'
          }`} 
          htmlFor={item.id}
        >
          {item.value}
        </label>
        <input 
          className="hidden" 
          type="radio" 
          id={item.id} 
          value={item.value} 
          name={'selectSize'}
          checked={selectedSize === item.value}
          // 这里可以保留onChange,也可以去掉,因为点击label已经会触发radio的change事件
          onChange={(e) => setSelectedSize(e.target.value)}
        />
      </div>
    ))}
  </div>
</div>

为什么这样更靠谱?

  1. 完全遵循React的数据流:状态变化驱动UI更新,避免手动操作DOM带来的潜在bug
  2. 不需要依赖useRef,彻底解决了ref指向错误的问题
  3. 代码更简洁,逻辑更清晰,后续维护起来也更方便

内容的提问来源于stack exchange,提问作者Jud3v Digital

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 16:27:32