admin管理员组

文章数量:1123711

My infinite scroll component for my images works swimmingly on a normal page, but the second I put it in the MUI Dialog it fails to trigger any response on scroll. I have tried some ref tricks and intersection observer changes as well but to no avail. Any help is appreciated!

Infinite Scroll Component

import React, { useRef, useCallback, useEffect, useState, Fragment, useId } from 'react';
import { useParams } from '@remix-run/react';
import { useInfiniteQuery } from 'react-query';
import { getImagesPage } from '../../../services/media.service';
import { Box, Typography, Paper, useMediaQuery, Skeleton, ImageList, ImageListItem, useTheme } from '@mui/material';
import FileUpload from '../../../utils/Buttons/FileUpload';
import { CameraAltOutlined } from '@mui/icons-material';

interface ImageScrollProps {
  listing: any;
  type: any;
  navigation: any;
  initialData?: any;
};

const ImageScroll: React.FC<ImageScrollProps> = ({ listing, type, navigation, initialData }) => {
  const { Id } = useParams<{ Id: string }>();
  const newId = useId();
  const theme = useTheme();
  const extraSmall = useMediaQuery(theme.breakpoints.only('xs'));
  const small = useMediaQuery(theme.breakpoints.only('sm'));
  const columns = extraSmall ? 2 : (small ? 3 : 4);
  const [imageCount, setImageCount] = useState<number>(0);
  const width = (extraSmall || small) ? 300 : 410;
  const [isLoading, setIsLoading] = useState(true);
  const [containerHeight, setContainerHeight] = useState('19em');

  const {
    fetchNextPage,
    hasNextPage,
    isFetchingNextPage,
    data,
    status,
    error
  } = useInfiniteQuery<any, any>(`/${Id}`, ({ pageParam = 1 }) => getImagesPage(Id, pageParam, type), {
    getNextPageParam: (lastPage: any, allPages: any) => {
      if (lastPage && lastPage.length > 0) {
        return allPages.length + 1;
      }
      return undefined;
    },
    // getNextPageParam: (lastPage: any, allPages: any) => {
    //   const nextPageNumber = allPages.length + 1;
    //   return lastPage.length ? nextPageNumber : undefined;
    // },
    initialData: initialData ? {
      pages: [initialData],
      pageParams: [1],
    } : undefined,
    onSettled: () => setIsLoading(false),
  });

  const allImages = data ? data.pages.flat() : [];

  useEffect(() => {
    if (data) {
      setImageCount(prevCount => prevCount + data.pages.flat().length);
    }
  }, [data]);

  // useEffect(() => {
  //   if (imageCount <= 2) {
  //     setContainerHeight('9.5em');
  //   }
  // }, []);

  useEffect(() => {
    return () => {
      if (intObserver.current) intObserver.current.disconnect()
    }
  }, [])

  // const containerHeight = imageCount <= 2 ? '9.5em' : '19em';

  const masonryContainerStyles = {
    height: '100vh',
    overflowY: 'auto',
    width: '100%',
    padding: '0em',
    borderRadius: '15px',
    '::WebkitScrollbar':
      { display: 'none' },
    msOverflowStyle: 'none',
    scrollbarWidth: 'none',
  };

  const intObserver = useRef();
  const lastImageRef = useCallback(image => {
    if (isFetchingNextPage) return;

    if (intObserver.current) intObserver.current.disconnect();

    intObserver.current = new IntersectionObserver(entries => {
      if (entries[0].isIntersecting && hasNextPage) {
        fetchNextPage();
      }
    }, { rootMargin: '200px' }); // Adjust this value as needed

    if (image) intObserver.current.observe(image);
  }, [isFetchingNextPage, fetchNextPage, hasNextPage]);

  if (isLoading) {
    return (
      <Box style={masonryContainerStyles} sx={{ display: 'flex', justifyContent: 'center' }}>
        <ImageList cols={2} gap={0} spacing={0} id='image-list'>
          {[...Array(8)].map((_, index) => (
            <Skeleton
              key={`skeleton-${index + 1}`}
              variant="rounded"
              animation="wave"
              width={180}
              height={118}
            />
          ))}
        </ImageList>
      </Box>
    );
  }

  const borderRadiusValue = '20px';

  const content = (
    <Box style={masonryContainerStyles} key={newId}>
      <ImageList variant='masonry' cols={columns} spacing={0} gap={0} id='image list'>
        {allImages.map((image, i) => {
          const isLastImage = i === allImages.length - 1;
          const uniqueKey = `${image._id}-${i}`;
          const imageWidth = Math.round(parseInt(image.width, 10) * 1);
          const imageHeight = Math.round(parseInt(image.height, 10) * 1);

          const mediaElement = image.mediaType === 'video' ? (
            <Box style={{ width: '100%', height: '100%', padding: 0, margin: 0, overflow: 'hidden' }} key={newId}>
              <video
                src={image.url}
                aria-label='Video card'
                id='video'
                style={{
                  maxWidth: "100%",
                  maxHeight: "auto",
                  objectFit: "cover",
                  padding: 0,
                  margin: 0,
                  borderRadius: borderRadiusValue
                }}
                autoPlay
                muted
                loop
                playsInline
              />
            </Box>
          ) : (
            <ImageListItem id={`image number ${uniqueKey}`} key={`image number - ${image._id}`}>
              <img
                src={image.url ?? ''}
                alt={image.alt ? image.alt : `${listing.name} image`}
                id={`image ${uniqueKey}`}
                aria-label='Image card'
                width={imageWidth}
                height={imageHeight}
                loading='eager'
                style={{
                  objectFit: "cover",
                  padding: 0,
                  margin: 0,
                  display: 'block',
                  borderRadius: borderRadiusValue,
                }}
              />
            </ImageListItem>
          );

          return (
            <>
              {/* {status === 'success' &&
                <Fragment> */}
              <div ref={isLastImage ? lastImageRef : null} width={width}>
                {mediaElement}
              </div>
              {/* </Fragment>
              } */}
            </>
          );
        })}
      </ImageList>
    </Box>
  );


  return (
    <>
      {status === 'error' && <p className='center'>Error: {error.message}</p>}
      {status === 'success' && (
        data?.pages && data.pages.flat().length > 0 ? content : (
          <Box sx={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: '100%' }}>
            <Paper sx={{ display: 'flex', width: '80%', minHeight: '10.5em', justifyContent: 'center', alignItems: 'center', flexDirection: 'column', maxHeight: '300px', '::WebkitScrollbar': { display: 'none' }, overflow: 'auto', backgroundColor: '#F1F0E9', }}>
              {
                (small || extraSmall) ? (
                  <Box sx={{ width: '100%', display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
                    <CameraAltOutlined size={'xl'} />
                    <Typography variant="h6">
                      Nothing yet, add something!
                    </Typography>
                  </Box>
                ) : (
                  <Box sx={{ width: '50%', display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
                    <CameraAltOutlined size={'xl'} />
                    <Typography variant="h6">
                      Nothing yet, be the first to add something!
                    </Typography>
                  </Box>
                )
              }
            </Paper>
          </Box>
        )
      )}
      {
        (!listing.media) &&
        <Box sx={{ marginLeft: { xl: '10em', lg: '9.5em', md: '8em', sm: '5em', xs: '2.8em' }, marginTop: '0.5em' }}>
          <FileUpload type={type} listingId={listing._id} navigation={navigation} aria-label='Upload media button' />
        </Box>
      }
      {
        (listing.media) &&
        <Box sx={{ marginLeft: '1em', marginTop: '0.5em' }}>
          <FileUpload type={type} listingId={listing._id} navigation={navigation} aria-label='Upload media button' />
        </Box>
      }
    </>
  );
}

export default React.memo(ImageScroll);

Dialog Below

import { Fragment, useState } from 'react';
import { SwipeableDrawer, CssBaseline, Button, Box, Typography, TextField, Divider, IconButton, Avatar, Dialog, DialogContent } from '@mui/material';
import loadable from '@loadable/component';
import { useUniversalDialogContext } from "~/services/Contexts/UniversalDialogContext";
import { Close } from '@mui/icons-material';

const ImageScroll = loadable(() => import('../InfiniteScroll/Images/ImageScroll'));

const Puller = () => (
    <Box
        sx={{
            width: 30,
            height: 6,
            backgroundColor: 'gray',
            borderRadius: 3,
            position: 'absolute',
            top: 8,
            left: 'calc(50% - 15px)',
        }}
    />
);

const ImageDialog = ({ listing, type, navigation, initialData }) => {
    const { openImageScroll, setOpenImageScroll } = useUniversalDialogContext();

    return (
        <Dialog
            fullScreen
            open={openImageScroll}
            onClose={() => setOpenImageScroll(false)}
            PaperProps={{
                sx: {
                    backgroundColor: 'background.paper',
                    overflow: 'hidden' // Prevent double scrollbars
                }
            }}
        >
            <Box sx={{
                position: 'absolute',
                right: 8,
                top: 8,
                zIndex: 1
            }}>
                <IconButton
                    edge="start"
                    color="inherit"
                    onClick={() => setOpenImageScroll(false)}
                    aria-label="close"
                >
                    <Close />
                </IconButton>
            </Box>

            <DialogContent sx={{
                p: 0,
                height: '100vh',
                overflow: 'auto',
                '&::-webkit-scrollbar': { display: 'none' },
                msOverflowStyle: 'none',
                scrollbarWidth: 'none'
            }}>
                <Box sx={{ pt: 6 }}> {/* Add padding top to account for close button */}
                    <ImageScroll
                        listing={listing}
                        type={type}
                        navigation={navigation}
                        initialData={initialData}
                    />
                </Box>
            </DialogContent>
        </Dialog>
    );
};

export default ImageDialog;

I have tried changing intersection observer, ref, and a few other window things but nothing works. I tried changing from a swipable drawer to this dialog and that did not work either.

本文标签: reactjsReact Query Infinite Scroll does not work in an MUI DialogStack Overflow