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

如何确保React状态按顺序更新?解决多选下拉框状态冲突

解决方案

问题原因

  1. React状态更新是异步批量处理的,同一事件周期内的多个setState会被合并执行,不会立即同步更新状态。
  2. 点击下拉选项时,input的onBlur事件会优先于li的onClick事件触发,导致showCategories先被设为false,下拉框提前卸载,干扰状态更新的视觉反馈。

方法一:用useEffect监听状态变化

通过useEffect钩子监听selectedCategoriesData的变化,确保选中数据更新完成后再隐藏下拉框,这是最可靠的实现方式。

修改后的Filter.jsx代码:

import { useState, useEffect } from "react";
import classes from "./Filter.module.css";

const Filter = ({ categories }) => {
  const [selectedCategoriesData, setSelectedCategoriesData] = useState([]);
  const [showCategories, setShowCategories] = useState(false);
  const handleCategoryInput = (e) => {};

  const handleCategorySelect = (categoryChosen) => {
    // 使用函数式更新,避免闭包导致的旧状态引用问题
    setSelectedCategoriesData(prev => [...prev, categoryChosen]);
  };

  // 监听选中数据变化,更新完成后隐藏下拉框
  useEffect(() => {
    if (selectedCategoriesData.length > 0) {
      setShowCategories(false);
    }
  }, [selectedCategoriesData]);

  return (
    <div className={classes.filter_container}>
      <div className="category_filter">
        <label htmlFor="ctgry">Category</label>
        <input
          className={classes.category_select}
          onChange={handleCategoryInput}
          onFocus={() => setShowCategories(true)}
          onBlur={() => setShowCategories(false)}
        ></input>
        {showCategories && (
          <ul className={classes.categories_data}>
            {categories.map((category, index) => (
              <li tabIndex={0} key={index} onClick={() => handleCategorySelect(category)}>
                <span>{category}</span>
              </li>
            ))}
          </ul>
        )}
      </div>
    </div>
  );
};

export default Filter;

方法二:阻止事件冒泡,避免onBlur提前触发

点击下拉选项时,阻止事件向上冒泡,避免input的onBlur事件提前触发,即可在handleCategorySelect中先更新状态,再手动隐藏下拉框。

修改li的点击事件处理:

<li 
  tabIndex={0} 
  key={index} 
  onClick={(e) => {
    e.stopPropagation(); // 阻止事件冒泡,避免触发input的onBlur
    handleCategorySelect(category);
    setShowCategories(false); // 此时可安全调用
  }}
>
  <span>{category}</span>
</li>

同时保持handleCategorySelect的函数式更新:

const handleCategorySelect = (categoryChosen) => {
  setSelectedCategoriesData(prev => [...prev, categoryChosen]);
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 15:47:28