I'm new and may have said the terms wrong I tried to write an infinite scroll from the code below github
By running the app, a few basic items are taken from the API, and when I scroll down, start changes, but a new request to get data is not sent.
my custom hook
import { useEffect, useState } from "react";
import { getData } from "../apis/coinmarketcapApi";
export default function useData({ start = 0 }) {
const [result, setResult] = useState([]);
const [error, setError] = useState({});
const [isError, setIsError] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const [hasNextPage, setHasNextPage] = useState(false);
console.log('start-useData :>> ', start);
useEffect(() => {
setIsLoading(true);
setIsError(false);
setError({});
const controller = new AbortController();
const { signal } = controller;
getData(start, { signal })
.then((response) => {
setResult((prev) => [...prev, ...response.data]);
setHasNextPage(Boolean(response.data.length));
setIsLoading(false);
})
.catch((e) => {
setIsLoading(false);
if (signal.aborted) return;
setIsError(true);
setError({ "axios error:": e });
});
return () => controller.abort();
}, [start]);
return { result, error, isError, isLoading, hasNextPage };
}
parent component
import React, { useState, useCallback, useRef } from "react";
import useData from "./hooks/useData";
import Post from "./Post";
export default function CryptoList() {
const [start, setStart] = useState(0);
const { result, error, isError, isLoading, hasNextPage } = useData(start);
console.log('start :>> ', start);
const intersectionObserver = useRef();
const lastDataRef = useCallback(
(data) => {
if (isLoading) return;
if (intersectionObserver.current)
intersectionObserver.current.disconnect();
intersectionObserver.current = new IntersectionObserver((entry) => {
if (entry[0].isIntersecting && hasNextPage)
setStart((prev) => prev + 10);
});
if (data) intersectionObserver.current.observe(data);
},
[hasNextPage, isLoading]
);
if (isError) return <h1>Error: {error.message}</h1>;
const content = result.map((data, index) => {
if (result.length === index + 1)
return <Post key={data.id} data={data} ref={lastDataRef} />;
return <Post key={data.id} data={data} />;
});
return (
<>
<h1>List of Crypto</h1>
{content}
{isLoading && <h2>Loading ...</h2>}
</>
);
}
console
i want to with change of state, custom hook re-render
The useData hook will be called only once when the component will be created. The hook function does not run on every rerender. To achieve your desired functionality, create another state inside your hook, and expose the setter function. By doing this, you can update the start state inside the hook and thus trigger useEffect.
import { useEffect, useState } from "react";
import { getData } from "../apis/coinmarketcapApi";
export default function useData() {
const [result, setResult] = useState([]);
const [error, setError] = useState({});
const [isError, setIsError] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const [hasNextPage, setHasNextPage] = useState(false);
const [start, setStart] = useState(0);
console.log('start-useData :>> ', start);
useEffect(() => {
setIsLoading(true);
setIsError(false);
setError({});
const controller = new AbortController();
const { signal } = controller;
getData(start, { signal })
.then((response) => {
setResult((prev) => [...prev, ...response.data]);
setHasNextPage(Boolean(response.data.length));
setIsLoading(false);
})
.catch((e) => {
setIsLoading(false);
if (signal.aborted) return;
setIsError(true);
setError({ "axios error:": e });
});
return () => controller.abort();
}, [start]);
return { result, error, isError, isLoading, hasNextPage, setStart };
}
Now you can use setStart inside a useEffect in the parent component