react-infinite-scroll-component组件在Drawer/Modal中无法下拉滚动加载的解决办法

问题:react-infinite-scroll-component组件在Drawer/Modal中,局部滚动的应用,按照官方示例使用scrollableTarget绑定id会存在无法下拉滚动的问题;

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={
    
    "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"));

解决方案参考:react-infinite-scroll-component官方Issue

猜你喜欢

转载自blog.csdn.net/xiadahai/article/details/129368248
今日推荐