问题:react-infinite-scroll-component组件在Drawer/Modal中,局部滚动的应用,按照官方示例使用scrollableTarget绑定id会存在无法下拉滚动的问题;
import {
render } from "react-dom";
import React, {
useCallback, useState } from "react";
import InfiniteScroll from "react-infinite-scroll-component";
import {
Drawer } from "antd";
const InfiniteScrollDrawer = ({
open, setOpen }) => {
const [items, setItems] = useState(Array.from({
length: 30 }));
const listItems = items.map((_, index) => <div key={
index}>{
index}</div>);
const [listItemsContainerRef, setListItemsContainerRef] = useState();
const onlistItemsContainerRefChange = useCallback((node) => {
if (node !== null) {
setListItemsContainerRef(node);
}
}, []);
return (
<Drawer
width={
"60%"}
destroyOnClose={
true} //关闭时销毁子元素,避免重新打开数据不会刷新
open={
open}
onClose={
() => setOpen(false)}
title={
"demo"}
>
<div style={
{
height: "100px" }}>非滚动区域</div>
<div
style={
{
height: "300px",
// height: 'calc(100vh - 100px)', // this works also
display: "flex",
flexDirection: "column",
background: "lightyellow"
}}
>
<div style={
{
padding: "20px", background: "lightblue" }}>Header</div>
<div id={
"scrollableDiv"} style={
{
overflow: "auto" }}>
<InfiniteScroll
dataLength={
listItems.length}
next={
() => {
window.setTimeout(() => {
setItems((prevItems) => [
...prevItems,
...Array.from({
length: 30 })
]);
}, 1500);
}}
hasMore={
true}
loader={
<p style={
{
color: "red" }}>...loading</p>}
scrollableTarget={
"scrollableDiv"}
>
{
listItems}
</InfiniteScroll>
</div>
</div>
</Drawer>
);
};
const App = () => {
const [open, setOpen] = useState(false); // faking modal show
return (
<div>
<button onClick={
() => setOpen(true)}>show</button>
<button onClick={
() => setOpen(false)}>hide</button>
<InfiniteScrollDrawer open={
open} setOpen={
setOpen} />
</div>
);
};
render(<App />, document.getElementById("root"));
解决方案:由于Drawer和Modal的渲染机制问题,需要确保能够成功绑定InfiniteScroll的滚动容器的scrollableTarget,因此采用ref实时获取滚动容器,并确保在ref有值时绑定nfiniteScroll;
codesandbox代码成功示例
import {
render } from "react-dom";
import React, {
useCallback, useState } from "react";
import InfiniteScroll from "react-infinite-scroll-component";
import {
Drawer } from "antd";
const InfiniteScrollDrawer = ({
open, setOpen }) => {
const [items, setItems] = useState(Array.from({
length: 30 }));
const listItems = items.map((_, index) => <div key={
index}>{
index}</div>);
const [listItemsContainerRef, setListItemsContainerRef] = useState();
const onlistItemsContainerRefChange = useCallback((node) => {
if (node !== null) {
setListItemsContainerRef(node);
}
}, []);
return (
<Drawer
width={
"60%"}
destroyOnClose={
true} //关闭时销毁子元素,避免重新打开数据不会刷新
open={
open}
onClose={
() => setOpen(false)}
title={
""}
>
<div style={
{
height: "100px" }}>非滚动区域</div>
<div
style={
{
height: "300px",
// height: 'calc(100vh - 100px)', // this works also
display: "flex",
flexDirection: "column",
background: "lightyellow"
}}
>
<div style={
{
padding: "20px", background: "lightblue" }}>Header</div>
<div ref={
onlistItemsContainerRefChange} style={
{
overflow: "auto" }}>
{
listItemsContainerRef && (
<InfiniteScroll
dataLength={
listItems.length}
next={
() => {
window.setTimeout(() => {
setItems((prevItems) => [
...prevItems,
...Array.from({
length: 30 })
]);
}, 1500);
}}
hasMore={
true}
loader={
<p style={
{
color: "red" }}>...loading</p>}
scrollableTarget={
listItemsContainerRef}
>
{
listItems}
</InfiniteScroll>
)}
</div>
</div>
</Drawer>
);
};
const App = () => {
const [open, setOpen] = useState(false); // faking modal show
return (
<div>
<button onClick={
() => setOpen(true)}>show</button>
<button onClick={
() => setOpen(false)}>hide</button>
<InfiniteScrollDrawer open={
open} setOpen={
setOpen} />
</div>
);
};
render(<App />, document.getElementById("root"));