0

I'm implementing infinite scrolling with search bar. So I need to bring 10 items each time I call API, incrementing page number by 1.

I used useState to increase pageNumber and called setPageNum before I call 'fetchMore' function in the child component. The problem is that it always initialized to 1 and it returns the same state, 2 only.

I've been trying every way that I know for about 5hrs but got stucked. What am I doing wrong and how would I be able to fix this?

const InputTodo = ({ setTodos }) => {
  const [inputText, setInputText] = useState("");
  const [suggestionList, setSuggestionList] = useState([]);
  const [params, setParams] = useState(null);
  const [pageNum, setPageNum] = useState(1);

  const debouncedText = useDebounce(inputText, 500);

  useEffect(() => {
    if (!debouncedText) {
      return;
    }
    async function fetchData() {
      const { data } = await getSearchSuggestion(debouncedText, 1);
      const { result, total, limit, page } = data;
      setPageNum(page);
      setSuggestionList(result || []);
      setParams({
        total,
        limit
      });
    }
    fetchData();
  }, [debouncedText]);

  const handleFetchMore = useCallback(
    async (query) => {
      if (params.total < params.limit * (pageNum - 1)) {
        return;
      }
      try {
        const { data } = await getSearchSuggestion(query, pageNum + 1);
        setSuggestionList((prev) => [...prev, ...data.result]);
        setPageNum(data.page);
      } catch (error) {
        console.log(error);
      }
    },
    [pageNum, params]
  );
//child component

const InputDropdown = ({
  query,
  suggestions,
  pageNum,
  setPageNum,
  limit,
  total,
  onFetchMore
}) => {
  const [isBottom, setIsBottom] = useState(null);
  const bottomObserver = useRef(null);

  useEffect(() => {
    const observer = new IntersectionObserver(
      (entries) => {
        if (entries[0].isIntersecting) {
          if (total < limit * pageNum) {
            return;
          }
          setPageNum((prev) => prev + 1);
          onFetchMore(query);
        }
      },
      { threshold: 0.25 }
    );
    bottomObserver.current = observer;
  }, []);
Ava Kim
  • 47
  • 1
  • 5

2 Answers2

0

The problem might be that you are changing the state in the useEffect hook. Since the dependency array of useEffect does not have pageNum in it, it wont run again.

turkishpeter
  • 44
  • 2
  • 5
0

I think it's because the prev value in setPageNum((prev) => prev + 1) is initialised only when the component mount and it's not refreshed.

To solve this problem you can call a handleTrigerObserver() function outside of your useEffect :

 const observer = new IntersectionObserver(
      entries => {
        if (entries[0].isIntersecting) {
          handleObserverTrigger();
        }
      },
      { threshold: 0.01 },
    );

you can store this function in a useCallback if you want to optimise the recalculate of this function on each render :

const handleObserverTrigger = useCallback( async () => {

     const newData = await getPagedData(intersectionCounter * 50, 50, filters)
     setData([ ...newData]);
     setPageNum(pageNum + 1);
   
  }, [ getPagedData, pageNum, filters]);

Here pageNum value will refresh on each render. in your observale it's set one time

H-DC
  • 92
  • 2