react-window:列表项变更时如何更新itemSize?过滤出现间隙
解决方案
你的问题核心是VariableSizeList会缓存列表项的高度值,当过滤导致navigation数组变化后,旧的高度缓存和新数据不匹配,从而出现布局间隙。以下是修复步骤:
1. 通过Ref获取列表实例
函数组件中不能直接通过resetAfterIndex属性重置缓存,需要先获取VariableSizeList的实例引用:
const listRef = useRef<VariableSizeList>(null);
2. 监听数据变化,重置高度缓存
当navigation数据更新时,调用实例的resetAfterIndex(0)方法,清除从第0项开始的所有高度缓存,让组件重新计算每个列表项的高度:
useEffect(() => { if (listRef.current) { listRef.current.resetAfterIndex(0); } }, [navigation]);
3. 修改后的完整代码
const Row = memo(function Row({ index, style, data: { navigation }, }: ListChildComponentProps<{ navigation: Navigation[]; }>) { const nav = navigation[index]; return ( <li key={nav.name} style={style}> <h3>{nav.name}</h3> {nav.children.map((child) => ( <Link key={child.name} href="#"> {child.name} </Link> ))} </li> ); }, areEqual); const getItemHeight = ({ navSection }: { navSection: Navigation }) => { return 36 + navSection.children.length * 36; }; function List() { const { navigation } = useContext(NavigationContext); const listRef = useRef<VariableSizeList>(null); const getItemSize = useCallback((index: number) => getItemHeight({ navSection: navigation[index] }), [navigation]); const getItemLength = useMemo(() => navigation.length, [navigation]); useEffect(() => { if (listRef.current) { listRef.current.resetAfterIndex(0); } }, [navigation]); return ( <AutoSizer> {({ height, width }: Size) => ( <VariableSizeList ref={listRef} className="scrollbar" height={height} itemCount={getItemLength} itemSize={getItemSize} width={width} itemData={{ navigation }} > {Row} </VariableSizeList> )} </AutoSizer> ); }
关键说明
useCallback本身的写法没问题,但VariableSizeList不会自动检测itemSize函数的变化来清除缓存,必须手动触发重置- 你之前尝试的
resetAfterIndex属性是类组件的用法,函数组件需要通过实例方法调用 - 调用
resetAfterIndex(0)会重置所有列表项的高度缓存,确保过滤后的新列表能正确计算每一行的高度
内容的提问来源于stack exchange,提问作者wongx
相关产品推荐
相关产品推荐

