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

muuri-react配合Redux报错“Invariant failed: The item has not been setted yet”如何解决?

问题根源

    1. 不稳定的key值:你用数组下标index作为Muuri子元素的key,notes2是Redux异步拉取的数据,首次渲染时notes2是空数组,此时渲染0个元素,数据返回后notes2变成3个元素,用index当key会让Muuri错误复用之前的虚拟节点状态,内部网格项的注册逻辑混乱,导致拖拽失效、渲染异常。
    1. 数组引用频繁变动:Object.values(state.notes.byId)每次执行都会返回全新的数组引用,useSelector默认做引用全等比较,哪怕数据内容没变化也会触发组件重渲染,Muuri对无意义的重渲染兼容性很差。
    1. 异步数据初始化时机不匹配:Muuri组件初始化的时候需要拿到完整的子元素列表,你现在初始化的时候notes2是空的,后续数据更新后Muuri没有正确同步新增的网格项状态,切换页面卸载组件时就会抛出Invariant failed: The item has not been setted yet的错误。

修复方案

1. 替换为稳定的唯一key

不要用index当key,直接用每个note自带的id作为key:

// notes1的map也同步修改,避免后续出问题
{notes1.map((note) => (
  <StyledNote key={note.id}>
    <h3>{note.title}</h3>
    <div>{note.text}</div>
  </StyledNote>
))}
// notes2同理
{notes2.map((note) => (
  <StyledNote key={note.id}>
    <h3>{note.title}</h3>
    <div>{note.text}</div>
  </StyledNote>
))}

2. 优化useSelector的缓存逻辑

给useSelector传入第二个参数比较函数,用lodash的isEqual做深比较,避免不必要的重渲染:

// 写法1:直接传比较函数
const notes2 = useSelector((state) => Object.values(state.notes.byId), _.isEqual)

// 写法2(性能更优):用createSelector做缓存selector
import { createSelector } from '@reduxjs/toolkit'
const selectNotes = createSelector(
  (state) => state.notes.byId,
  (byId) => Object.values(byId)
)
// 组件内使用
const notes2 = useSelector(selectNotes)

3. 等数据加载完成后再渲染Muuri组件

给notes2加加载判断,初始为空的时候不渲染Muuri,等数据返回后再渲染,保证Muuri初始化的时候有完整的子元素列表:

<MuuriWrapper>
  {notes2.length > 0 && (
    <MuuriComponent dragEnabled dragFixed>
      {notes2.map((note) => (
        <StyledNote key={note.id}>
          <h3>{note.title}</h3>
          <div>{note.text}</div>
        </StyledNote>
      ))}
    </MuuriComponent>
  )}
</MuuriWrapper>

以上修改完成后即可解决渲染异常、拖拽失效、切换页面报错的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 07:54:03