题记: 最近 有一个项目升级 react18后,antd 的一个列表页突然无法加载更多了。这个列表在一个 Modal 的对话框中,带着疑问排查了后,记录下。
这是 Antd 官方的加载更多例子。
官方示例中,通过 scrollableTarget 关联了外部的 Div,通过外部 DIV 来控制监听加载更多和下拉加载的实现。
我们将官方示例放到一个 Modal 中显示,就会复现BUG 了。会发现无法触发 Next函数等问题。
通过排查,问题就出在了这个scrollableTarget。这里可以看到react-infinite-scroll-component 的源码的这一段。
可以看到组件在挂载的时候去初始化的滚动节点绑定。因为渲染顺序是 子节点的挂载后,挂载父节点。而scrollableTarget 初始化的时候,他的父DIV 还没有挂载上去,所以document.getElementById()获取到的是 null,导致了绑定失败。
知道了问题就好解决了。
解决
我们只需要确定父类 div 挂载成功后去渲染列表页就可以了。
我们将官方例子简单调整下:
const App: React.FC = () => {
const [loading, setLoading] = useState(false);
const [data, setData] = useState<DataType[]>([]);
/// 第一步: 创建一个引用
const refScrollBody = useRef<HTMLDivElement>();
///======官方中间的加载函数等被删除了=========
/// ...官方Demo这里有一些函数,
/// https://ant-design.gitee.io/components/list-cn#components-list-demo-infinite-load
///=======================================
return (
//第二步:设置引用节点
<div
id="scrollableDiv"
ref={refScrollBody}
style={{
height: 400,
overflow: "auto",
padding: "0 16px",
border: "1px solid rgba(140, 140, 140, 0.35)",
}}
>
//第三步:在这里判断存在父节点后渲染
{refScrollBody.current && <InfiniteScroll
dataLength={data.length}
next={loadMoreData}
hasMore={data.length < 50}
loader={<Skeleton avatar paragraph={{ rows: 1 }} active />}
endMessage={<Divider plain>It is all, nothing more 🤐</Divider>}
scrollableTarget={refScrollBody.current.id}
>
<List
dataSource={data}
renderItem={(item) => (
<List.Item key={item.email}>
<List.Item.Meta
avatar={<Avatar src={item.picture.large} />}
title={<a href="https://ant.design">{item.name.last}</a>}
description={item.email}
/>
<div>Content</div>
</List.Item>
)}
/>
</InfiniteScroll>}
</div>
);
};
最后,我把改动的地方圈一下。
另外,发现 github 上有一个 open 的 issue 和这个问题相关。 github.com/ankeetmaini…
好的,搞定~