Problem with update state in React with Intersection observer

29 views Asked by At

import {
  Box
} from '@mui/material';
import {
  useCallback,
  useEffect,
  useRef,
  useState
} from 'react';

export const patientResults = {
  items: [{
      firstName: 'John',
      lastName: 'Doe',
      dob: '1990-05-15'
    },
    {
      firstName: 'Alice',
      lastName: 'Smith',
      dob: '1985-12-28'
    },
    {
      firstName: 'Bob',
      lastName: 'Johnson',
      dob: '1993-08-03'
    },
    {
      firstName: 'Emma',
      lastName: 'Brown',
      dob: '1988-02-17'
    },
    {
      firstName: 'David',
      lastName: 'Williams',
      dob: '1995-11-09'
    },
    {
      firstName: 'Olivia',
      lastName: 'Jones',
      dob: '1982-06-25'
    },
    {
      firstName: 'Michael',
      lastName: 'Miller',
      dob: '1991-04-02'
    },
    {
      firstName: 'Sophia',
      lastName: 'Davis',
      dob: '1987-09-14'
    },
    {
      firstName: 'Daniel',
      lastName: 'Taylor',
      dob: '1998-01-31'
    },
    {
      firstName: 'Ava',
      lastName: 'Anderson',
      dob: '1984-07-22'
    },
    {
      firstName: 'Matthew',
      lastName: 'Moore',
      dob: '1996-12-07'
    },
    {
      firstName: 'Isabella',
      lastName: 'Wilson',
      dob: '1989-03-18'
    },
    {
      firstName: 'Ethan',
      lastName: 'White',
      dob: '1994-10-12'
    },
    {
      firstName: 'Mia',
      lastName: 'Harris',
      dob: '1983-08-29'
    },
    {
      firstName: 'Alexander',
      lastName: 'Martin',
      dob: '1992-02-05'
    },
    {
      firstName: 'Emma',
      lastName: 'Thomas',
      dob: '1986-05-20'
    },
    {
      firstName: 'William',
      lastName: 'Clark',
      dob: '1997-09-03'
    },
    {
      firstName: 'Sophia',
      lastName: 'Robinson',
      dob: '1981-11-26'
    },
    {
      firstName: 'James',
      lastName: 'Baker',
      dob: '1999-06-10'
    },
    {
      firstName: 'Ava',
      lastName: 'Green',
      dob: '1980-01-15'
    },
    {
      firstName: 'Benjamin',
      lastName: 'Adams',
      dob: '1990-07-30'
    },
    {
      firstName: 'Olivia',
      lastName: 'Lee',
      dob: '1985-04-13'
    },
    {
      firstName: 'Lucas',
      lastName: 'Hall',
      dob: '1993-10-28'
    },
    {
      firstName: 'Amelia',
      lastName: 'Carter',
      dob: '1988-03-21'
    },
    {
      firstName: 'Jackson',
      lastName: 'King',
      dob: '1995-12-16'
    },
    {
      firstName: 'Ella',
      lastName: 'Ward',
      dob: '1982-08-07'
    },
    {
      firstName: 'Liam',
      lastName: 'Turner',
      dob: '1991-01-22'
    },
    {
      firstName: 'Grace',
      lastName: 'Scott',
      dob: '1986-06-06'
    },
    {
      firstName: 'Logan',
      lastName: 'Evans',
      dob: '1998-04-01'
    },
    {
      firstName: 'Chloe',
      lastName: 'Parker',
      dob: '1983-09-24'
    },
    {
      firstName: 'Joel',
      lastName: 'Ferguson',
      dob: '1990-05-15'
    },
    {
      firstName: 'Lenora',
      lastName: 'Young',
      dob: '1985-12-28'
    },
    {
      firstName: 'Brandon',
      lastName: 'Wolfe',
      dob: '1993-08-03'
    },
    {
      firstName: 'Jesus',
      lastName: 'Kelly',
      dob: '1988-02-17'
    },
    {
      firstName: 'Alex',
      lastName: 'Norris',
      dob: '1995-11-09'
    },
    {
      firstName: 'Leah',
      lastName: 'Holt',
      dob: '1982-06-25'
    },
    {
      firstName: 'Frances',
      lastName: 'Campbell',
      dob: '1991-04-02'
    },
    {
      firstName: 'William',
      lastName: 'McLaughlin',
      dob: '1987-09-14'
    },
    {
      firstName: 'Maude',
      lastName: 'Hansen',
      dob: '1998-01-31'
    },
    {
      firstName: 'Gilbert',
      lastName: 'McCormick',
      dob: '1984-07-22'
    },
    {
      firstName: 'Hunter',
      lastName: 'Hampton',
      dob: '1996-12-07'
    },
  ],
};

const PER_PAGE = 10;

const InfiniteScrollObserver = () => {
  const [items, setItems] = useState < {
    firstName: string;lastName: string;dob: string
  }[] > ([]);

  const [loading, setLoading] = useState(false);
  const [page, setPage] = useState(1);
  const [startIndex, setStartIndex] = useState(0);
  const [endIndex, setEndIndex] = useState(PER_PAGE);
  const [hasMore, setHasMore] = useState(true);

  const observer = useRef < IntersectionObserver | null > (null);

  const loadMoreItems = () => {
    console.log(startIndex, endIndex); // always the same result, never changed
    console.log(page, 'page') // page is also always the same
    const newItems = patientResults.items.slice(startIndex, endIndex);
    setItems((prevItems) => [...prevItems, ...newItems]);
    setLoading(false);
  };

  const lastItemElementRef = useCallback(
    (node: HTMLDivElement) => {
      if (loading) return;
      if (observer.current) observer.current.disconnect();
      observer.current = new IntersectionObserver(
        (entries) => {
          if (entries[0].isIntersecting && hasMore) {
            setPage((prevPageNumber) => prevPageNumber + 1);
            loadMoreItems();
          }
        }, {
          threshold: 0.1,
        }
      );
      if (node) observer.current.observe(node);
    }, [loading, hasMore]
  );

  useEffect(() => {
    loadMoreItems();
  }, []);

  useEffect(() => {
    console.log(startIndex, endIndex); // here is updated
    setHasMore(patientResults.items.length > items.length);
    setStartIndex((prevPage) => prevPage + PER_PAGE);
    setEndIndex((prevEndIndex) => prevEndIndex + PER_PAGE);
  }, [items]);

  return ( <
    Box className = "flex f-column i-center"
    width = {
      '90vw'
    } > {
      items.map((item, index) => {
        if (items.length === index + 1) {
          return ( <
            div key = {
              index
            }
            ref = {
              lastItemElementRef
            }
            className = "last-index"
            style = {
              {
                height: 150
              }
            } > {
              index + 1
            } {
              item.firstName
            } {
              item.lastName
            } - {
              item.dob
            } <
            /div>
          );
        } else {
          return ( <
            div key = {
              index
            }
            style = {
              {
                height: 150
              }
            } > {
              index + 1
            } {
              item.firstName
            } {
              item.lastName
            } - {
              item.dob
            } <
            /div>
          );
        }
      })
    } {
      loading ? ( <
        Box position = "fixed"
        bottom = {
          0
        }
        left = {
          0
        }
        width = {
          '100vw'
        }
        className = "flex j-center"
        bgcolor = {
          'text.secondary'
        }
        color = {
          'white'
        } >
        <
        p > Loading... < /p> < /
        Box >
      ) : ( <
        >
        <
        />
      )
    } <
    /Box>
  );
};

export default InfiniteScrollObserver;

I have problem in loadMoreItems function that startIndex & endIndex is always the same so every time on calling this function it returns the same items (first 10 items from patientResults).

enter image description here

So, like is shown in the image, on results 47-50 I am getting actually results from 7-10 from the patientResults.items array.

What is problem with state, why these states aren't updated in loadMoreItems() function? Please help!

0

There are 0 answers