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

使用useMemo渲染map元素时自定义组件重复渲染如何解决?

问题根因

  • 核心原因是你用了条件渲染控制列表的显示/隐藏:当loading变为true时,memoData对应的整个列表DOM会被直接卸载;3秒后先执行setLoading(false)让列表重新挂载,此时items还是旧值[1],所以会先渲染一次id为1的Item,紧接着执行setItems(newArray)更新列表,又渲染一次id为4的Item,就出现了两次打印。
  • 次要问题:Item组件的useEffect依赖整个props对象,浅比较下每次props引用变化都会触发副作用执行,即使id没有变化。

修正方案

  1. 把条件渲染改成样式控制显示隐藏,避免列表组件被反复卸载挂载:
    把原来的条件渲染代码:
<div>{loading ? <label>{"Loading"}</label> : <div>{memoData}</div>}</div>

改成用display控制显隐:

<div>
  <label style={{display: loading ? 'block' : 'none'}}>Loading</label>
  <div style={{display: loading ? 'none' : 'block'}}>{memoData}</div>
</div>
  1. 优化Item组件的useEffect依赖,只依赖实际用到的id属性,避免不必要的副作用触发:
useEffect(() => {
  // call api with props.id
}, [props.id]);
  1. 可选优化:如果后续要扩展渲染逻辑,把renderItems用useCallback包裹,同时添加到useMemo的依赖数组中,符合React hook的依赖规则:
const renderItems = useCallback((item, index) => {
  return (
    <div key={item}>
      <Item id={item}></Item>
    </div>
  );
}, []);

const memoData = useMemo(() => {
  return <div>{items.map(renderItems)}</div>;
}, [items, renderItems]);

如果是React18之前的版本,setTimeout异步回调中的两次状态更新不会自动批处理,也可以把setLoading(false)和setItems(newArray)用ReactDOM.unstable_batchedUpdates包裹,或者把loading和items合并为同一个state对象一次性更新,也能避免两次重渲染。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 22:54:00