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

React组件更新时数组重复添加,!includes校验失效问题求助

问题原因与解决方案

核心问题分析

  1. 直接修改React State:你用searchResults.push(data)直接修改了state数组,React的state是不可变的,这种修改不会触发组件重新渲染,后续的state更新还会覆盖这种无效修改。
  2. 对象引用导致去重失效:Array.includes()对对象采用引用比较,从Firebase返回的每个doc.data()都是新创建的对象,哪怕内容完全一致,引用地址也不同,所以!searchResults.includes(data)永远为true,去重逻辑完全失效。
  3. 闭包捕获旧state:你的useEffect依赖是空数组,里面捕获的searchResults是组件初始渲染时的空数组,所以每次遍历都会执行push操作。

修复后的代码

const Directory = () => {
  const [searchResults, setSearchResults] = useState([]);
  const [loading, setLoading] = useState(false);
  const { currentUser } = useContext(AuthContext);

  useEffect(() => {
    setLoading(true);
    const fetchDoctors = async () => {
      const q = query(collection(db, "users"), where("type", "==", "doctor"));
      const querySnapshot = await getDocs(q);
      
      // 整理数据,把Firebase文档的唯一id加入对象,作为去重标识
      const newDoctors = querySnapshot.docs.map(doc => ({
        id: doc.id,
        ...doc.data()
      }));
      
      // 用函数式更新state,基于最新的state做去重
      setSearchResults(prevResults => {
        // 过滤掉已存在的医生(通过id判断)
        const uniqueNewDoctors = newDoctors.filter(newDoc => 
          !prevResults.some(existingDoc => existingDoc.id === newDoc.id)
        );
        // 合并旧数组和去重后的新数组
        return [...prevResults, ...uniqueNewDoctors];
      });
      
      setLoading(false);
    };
    fetchDoctors();
  }, []);

  console.log(searchResults);
  // 其他组件逻辑...
};

关键修复点

  • 函数式更新state:setSearchResults(prevResults => ...)确保每次更新都基于最新的state值,避开闭包问题。
  • 基于唯一标识去重:用Firebase文档的doc.id作为判断依据,通过prevResults.some()检查是否已存在,解决对象引用比较的问题。
  • 遵循state不可变原则:通过展开运算符创建新数组,不直接修改原state。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 05:20:43