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

