Reputation: 285
This might be very simple JS, but can't seem to get my head around it.
The nextPage
and prevPage
functions/buttons seem to call the loadNewProducts
function before updating the pageNum state.
When i click 'next' it changes state of pageNum to '2' but loads page 1. Then i click previous and it changes state of pageNum to '1' but loads page 2...
const [pageNum, setPage] = useState(1);
const [products, setProducts] = useState([]);
const [loading, setLoading] = useState(false);
const loadNewProducts = async () => {
setLoading(true);
const req = await fetch(`/api/nhan/${pageNum}`);
const json = await req.json();
setProducts(json);
console.log(products);
setLoading(false);
};
const nextPage = () => {
setPage(pageNum + 1);
loadNewProducts();
};
const prevPage = () => {
setPage(pageNum - 1);
loadNewProducts();
};
if (pageNum <= 0) {
setPage(1);
}
return (
<>
<NavBar />
<div>
<Head>
<title>Create Next App</title>
<meta name="description" content="Generated by create next app" />
<link rel="icon" href="/favicon.ico" />
</Head>
<button onClick={loadNewProducts}> Load </button>
<button onClick={prevPage}>Previous</button>
<button onClick={nextPage}>Next</button> Page {pageNum}
{loading && <div>LOADING</div>}
<NewProducts newProducts={products} />
</div>
</>
);
}
Upvotes: 0
Views: 1089
Reputation: 104
setPage
is a state updating function which is asynchronous in nature. So instate of using setPage(pageNum + 1)
, which might pick up the old state, you should you another overload of the state updating function where you receive old state as an argument. like below
const nextPage = () => {
setPage(pageNum => pageNum + 1);
};
const prevPage = () => {
setPage(pageNum => pageNum - 1);
};
Upvotes: 1
Reputation: 12777
Because setState
is async. It only has new value when component re-render. So you should use useEffect
in this case:
const nextPage = () => {
setPage(pageNum + 1);
};
const prevPage = () => {
setPage(pageNum - 1);
};
useEffect(() => {loadNewProducts()}, [pageNum])
Upvotes: 1
Reputation: 943207
Calling setPage
will asynchronously update the state and trigger a rerender.
This will cause the component function to run again and, when it does, pageNum
will be assigned a different value from the state by useState
.
However, first the nextPage
function will continue to run having closed over the old value of pageNum
.
To handle this, use a useEfect
hook with a dependency on pageNum
to run loadNewProducts
.
const nextPage = () => setPage(pageNum + 1);
const prevPage = () => setPage((pageNum - 1) || 1); // This stops you setting it to 0 in the first place
useEffect(() => {
const loadNewProducts = async () => {
setLoading(true);
const req = await fetch(`/api/nhan/${pageNum}`);
const json = await req.json();
setProducts(json);
setLoading(false);
};
loadNewProducts();
}, [pageNum, setLoading, setProducts]);
useEffect(() => {
console.log(products);
}, [products]);
Upvotes: 4