2

So I'm working on a website that has infinite scrolling and sorting/filtering. The issue is that when the sortBy method is being changed, I need to reset the offset for the pagination for the infinite scrolling page.

Here's the code for the component:

function Listings({ setListingCount, sortBy }) {
  const [listings, setListings] = useState([]);
  const [isInitialLoading, setIsInitialLoading] = useState(true);
  const [isLoading, setIsLoading] = useState(true);
  const [apiError, setApiError] = useState(false);
  const [offset, setOffset] = useState(0);
  const [hasMore, setHasMore] = useState(true);
  const limit = 12;

  const observer = useRef();
  const lastListingElementRef = useCallback((node) => {
    if (isLoading) {
      return;
    }

    if (observer.current) {
      observer.current.disconnect();
    }

    observer.current = new IntersectionObserver((entries) => 
  {
      if (entries[0].isIntersecting && hasMore) {
        setOffset((prevOffset) => prevOffset + limit);
      }
    });
    if (node) {
      observer.current.observe(node);
    }
  }, [isLoading, hasMore]);

  function resetListings() {
    setListings([]);
    setIsInitialLoading(true);
    setApiError(false);
    setOffset(0);
    setHasMore(true);
    setListingCount('0');
  }

  useEffect(() => {
    resetListings();
  }, [sortBy]);

  useEffect(async () => {
    try {
      setIsLoading(true);
      const response = await axios.get(
        'listings',
        {
          params: {
            offset,
            limit,
            sb: sortBy
          }
        }
      );
      setListings((prevListingIds) => [
        ...new Set(
          [...prevListingIds, ...response.data.rows]
        )
      ]);
      setListingCount(response.data.count);
      setHasMore(response.data.rows.length > 0);
      setIsLoading(false);
      setIsInitialLoading(false);
    } catch (error) {
      setApiError(true);
      setIsLoading(false);
      setIsInitialLoading(false);
    }
  }, [sortBy, offset]);

  return();
}

The first useEffect is being used to reset the states if the sortBy changes. The second useEffect is being used to load more data whenever the offset changes or if the sortBy changes. What's happening currently is when the user changes the sortBy when offset is not 0 (let's say 12), then the second useEffect is making a get request with offset = 12 before the first useEffect is able to reset the offset back to 0. But once the offset is reset to 0 by the first useEffect, another get request is made with offset = 0, so now it renders 24 listings instead of 12, and it's in the wrong order.

How should I be dealing with useEffects that aren't guaranteed to run in the order that I expect it to? Is there another way to implement this logic? Thank you for any help that can be provided!

DTan13
  • 428
  • 6
  • 16
  • I am a bit confused, but I'm trying to understand. The order of the useEffect() calls is based on the order they're triggered. I would look closely at that. Also the async could be messing you up. Looking at the state management you have here, I would suggest you set a boolean state value or anything additional. Then you can use that in your useEffect. Say you called it [needsUpdate, setNeedsUpdate]. At the end of the useEffect you can change the state of needs update and fire the other use effect. – sloont Jun 09 '21 at 02:01
  • This way, the change of the values doesn't trigger the useEffect, the change of the new value does. Additionally, setState will fire a rerender for you on affected components. – sloont Jun 09 '21 at 02:03
  • @sloont Hey thanks for your response! So I'm giving that a try right now, but I'm running into an issue because I need the second useEffect to run either when the offset changes or when the sortBy changes. But offset also needs to be reset to 0 when sortBy changes. So if I set `needsUpdate` to `true` at the end of the first useEffect, the second useEffect would still be triggered twice: once when `offset` is set to 0 and once when `needsUpdate` is set to true. This is with me changing the dependency variables for the second useEffect to `[needsUpdate, offset]`. Hope this is making sense – Kenneth Lee Jun 09 '21 at 02:42
  • I'm not quite sure the best way to go about this. You could potentially make sections of the functions into promises, then Promise.all so you wait for each process to end before you progress. – sloont Jun 09 '21 at 02:52

0 Answers0