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

React单选按钮仅识别上一次点击问题排查与修复请求

解决React单选按钮筛选产品时无法获取当前点击值的问题

问题核心原因

  1. React的useState更新是异步批量处理的,在handleRadioChange中调用setSelected后立刻执行getProductByCategory,此时selected还是更新前的旧值,导致请求参数错误。
  2. 单选按钮使用onClick而非标准的onChange事件,且label的for属性未正确对应input的id,影响交互逻辑。
  3. 后端查询分类时使用Category.find()返回数组,无法与Product的category字段(ObjectId类型)匹配,导致产品查询失败。

前端代码修改(Homepage.jsx)

方案1:直接传递当前选中值给查询函数

修改handleRadioChange,将点击的单选按钮值直接传入getProductByCategory,绕过异步状态更新的延迟:

const handleRadioChange = (e) => {
  const selectedValue = e.target.value;
  console.log(selectedValue);
  setSelected(selectedValue);
  getProductByCategory(selectedValue); // 直接传当前值
};

// 重构getProductByCategory,接收参数
const getProductByCategory = async (selectedValue) => {
  try {
    console.log(selectedValue);
    if (selectedValue === "all") {
      const { data } = await axios.get("http://localhost:5000/api/product");
      setProducts(data.products);
    } else {
      const { data } = await axios.get(`http://localhost:5000/api/product/${selectedValue}`);
      setProducts(data.products);
    }
  } catch (error) {
    console.log(error);
  }
};

方案2:使用useEffect监听selected状态变化

删除handleRadioChange中的getProductByCategory调用,添加useEffect监听selected的变化,自动触发查询:

const handleRadioChange = (e) => {
  setSelected(e.target.value);
};

// 添加useEffect监听selected
useEffect(() => {
  getProductByCategory();
}, [selected]); // 依赖selected,状态变化时执行

// 保留原getProductByCategory函数
const getProductByCategory = async () => {
  try {
    console.log(selected);
    if (selected === "all") {
      const { data } = await axios.get("http://localhost:5000/api/product");
      setProducts(data.products);
    } else {
      const { data } = await axios.get(`http://localhost:5000/api/product/${selected}`);
      setProducts(data.products);
    }
  } catch (error) {
    console.log(error);
  }
};

额外修复:单选按钮交互优化

  • 将onClick替换为onChange(表单元素的标准事件)
  • 修正label的for属性,使其对应input的id:
// 修复"All"选项的label
<div className="flex gap-3">
  <input 
    type="radio" 
    id="all" 
    name="category" 
    value="all" 
    onChange={handleRadioChange} // 替换为onChange
    checked={selected === "all"} 
  />
  <label htmlFor="all">All</label> {/* for对应input的id */}
</div>

// 修复分类循环中的label
{categories?.map((category) => (
  <div className="flex gap-3" key={category._id}> {/* 添加key属性 */}
    <input 
      type="radio" 
      id={category._id} 
      name="category" 
      value={category.slug} 
      onChange={handleRadioChange} // 替换为onChange
      checked={selected === category.slug} 
    />
    <label htmlFor={category._id}>{category.name}</label> {/* for对应input的id */}
  </div>
))}

后端代码修改(controllers/product.js)

将Category.find()改为Category.findOne(),获取单个分类文档的_id来匹配产品:

export const getProductByCategory = async(req,res) => {
    try{
        // 用findOne获取单个分类文档,而非数组
        const category = await Category.findOne({ slug: req.params.pslug })
        if(!category) {
            return res.status(404).json({
                success: false,
                message: "Category not found"
            })
        }
        // 使用分类的_id查询产品
        const products = await Product.find({ category: category._id }).select("-photo").populate("category")
        res.status(200).json({success: true, products}) // 状态码改为200(成功获取资源用200,创建用201)
    } catch(err){
        console.log(err)
        res.status(500).json({
            success: false,
            message: "Error in fetching products by category",
            err
        })
    }
}

补充优化

  • 在组件挂载时调用getProductByCategory,初始化展示所有产品:
useEffect(() => {
  getAllCategories();
  getProductByCategory();
}, []);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 05:49:52