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

React衍生状态问题:这段代码存在哪些问题?

React代码未用useMemo/useRef的深层问题解析(针对你的场景)

一、未用useMemo处理过滤逻辑的核心问题

  • 无意义的重复计算:只要组件触发渲染(哪怕searchTerm没变化,比如父组件传的其他props更新、组件自身其他state变动),过滤逻辑就会重新执行一次。如果products数据量较大(比如几百上千条),这会额外消耗CPU资源,在移动端低配置设备或性能敏感场景下,可能导致页面响应变慢。
  • 触发子组件不必要重渲染:如果过滤后的filteredProducts作为props传给子组件,没加useMemo的话,每次组件渲染都会生成一个全新的数组引用(哪怕数组内容完全一致)。React的props浅比较会判定props发生变化,进而触发子组件重渲染——这是最常见的性能浪费点,而你只监测了当前组件的渲染次数,没关注子组件,所以没发现差异。

二、未用useRef存储products的潜在问题

分两种常见场景:

  • products是父组件传入的props:如果父组件每次渲染都生成新的products数组(比如用[...originalData]这种写法,哪怕内容没变化),React会判定props更新,导致当前组件无意义重渲染。用useRef存储的话,可以通过useEffect对比内容,仅当products真的变更时才更新ref,避免触发不必要的过滤逻辑。
  • products是异步获取的数据:存到useRef里可以让你在定时器、事件回调等异步场景中,始终访问到最新的products数据,而不会因为组件渲染闭包问题拿到旧值。如果是静态初始化的数据,用不用useRef影响不大。

三、为什么你测渲染次数没发现差异?

你只关注了当前组件的渲染次数,但问题核心不在这:

  • 当searchTerm变化时,不管用不用useMemo,当前组件都会因state更新触发渲染,所以次数一致。
  • 真正的差异体现在渲染过程中的计算开销和子组件渲染次数:不用useMemo时,只要组件因其他原因渲染,过滤逻辑就会重复执行;若有子组件接收过滤结果,子组件会跟着无意义重渲染。

举个真实场景的代码对比

未优化版(你的当前代码大概率类似)

function ProductList({ products }) {
  const [searchTerm, setSearchTerm] = useState('');
  
  // 每次渲染都会重新执行过滤
  const filteredProducts = products.filter(item => 
    item.name.includes(searchTerm)
  );

  return (
    <div>
      <input onChange={(e) => setSearchTerm(e.target.value)} />
      <ProductItems items={filteredProducts} />
    </div>
  );
}

只要父组件重新渲染(哪怕products和searchTerm都没变),filteredProducts会生成新数组,导致ProductItems强制重渲染。

优化版

function ProductList({ products }) {
  const [searchTerm, setSearchTerm] = useState('');
  const productsRef = useRef(products);

  // 仅当products内容真正变化时更新ref
  useEffect(() => {
    if (JSON.stringify(products) !== JSON.stringify(productsRef.current)) {
      productsRef.current = products;
    }
  }, [products]);

  // 仅当searchTerm或products变化时重新过滤
  const filteredProducts = useMemo(() => {
    return productsRef.current.filter(item => item.name.includes(searchTerm));
  }, [searchTerm, productsRef.current]);

  return (
    <div>
      <input onChange={(e) => setSearchTerm(e.target.value)} />
      <ProductItems items={filteredProducts} />
    </div>
  );
}

这样只有searchTerm或products真的变化时,才会执行过滤,子组件也仅在filteredProducts内容变更时重渲染。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 02:12:13