I am trying to access the state variable val
inside my function addToFeed()
. In the first line of code inside addToFeed()
, the line console.log("Value of val: " val)
always prints out "Value of val:" (indicating val
can't be found, or it doesn't exist at that point). Why does this happen? And how can I get the value of val
to be found at that point in the code? (the value of val
does exist - I just can't access it).
Overall goal of code: Create an infinite scrolling list of posts from MongoDB that loads in as the user scrolls to the bottom of the page (this functionality is working, except it won't load the newest posts if my val
variable is never passed to my API).
Here is my code (below the code is a brief explanation of what it does to help with context):
import { useState, useEffect, useRef, useCallback } from "react";
export default function Feed() {
const [loading, setLoading] = useState(true);
const [error, setError] = useState(false);
const [posts, setPosts] = useState([]);
const [val, setVal] = useState(""); // VALUE I WANT TO ACCESS
const [hasMore, setHasMore] = useState(true);
const observer = useRef()
const lastItemRef = useCallback(node => {
if (loading) return;
if (observer.current) observer.current.disconnect();
observer.current = new IntersectionObserver(entries => {
if (entries[0].isIntersecting) {
addToFeed();
}
});
if (node) observer.current.observe(node);
}, [loading]);
useEffect(() => {
return () => {
setLoading(true);
addToFeed();
setLoading(false);
}
}, [])
async function addToFeed() {
console.log("Value of 'val': " val) // 'val' CAN'T BE FOUND HERE (need it below for the body of my api call)
try {
if (hasMore) {
await fetch("http://localhost:3000/api/load-forever-api", {
method: "POST",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(val)
}).then(res => res.json())
.then(data => {
setVal(data.posts[data.posts.length - 1].id)
setPosts(prev => {
return [...prev, ...data.posts]
})
setHasMore(data.hasMore)
});
}
}
catch (error) {
setError(true);
}
}
// UI RETURNED BELOW
if (loading) return <p>Loading...</p>
if (error) return <p>Error</p>
return (
<>
<h2>{`Value: ${val}`}</h2>
{posts.map((item, index) => {
if (posts.length === index 1) {
return (
<div className="shaded-post" ref={lastItemRef} key={index}>
<h3>{item.title}</h3>
<p>{item.body}</p>
<p>{item.id}</p>
<br />
</div>
)
} else {
return (
<div className="shaded-post" key={index}>
<h3>{item.title}</h3>
<p>{item.body}</p>
<p>{item.id}</p>
<br />
</div>
)
}
})}
</>
)
}
Additional info:
My API call returns a list of objects with title
, body
, and id
fields (MongoDB call). (ex: [{title: "ex1", body: "ex1", id: "123k8al29slkd"}, {title: "ex2", body: "ex2", id: "823jald8sj22"}]
If my API call receives a body with a blank val
variable, it returns the first 4 items from my MongoDB collection, if it has an id variable, I use that to return just the items from my MongoDB collection that were posted later than that (basically, this allows incremental infinite scrolling; loads the first 4, then if the user scrolls low enough it'll load the next 4, etc. etc.)
My val
variable updates every time I trigger the addToFeed()
function, assigning it the value of the id
from the last item on screen (infinite scrolling).
My addToFeed()
function adds to my posts
state, which is rendered as a list of items from my MongoDB database. Calling it multiple times when the user scrolls to the bottom of the pages creates the effect of an "infinite scroll".
I have 3 states that the UI can render: loading, error, and my infinite scrollable list of items from MongoDB.
CodePudding user response:
The reason why you are not getting the val
value is that when component renders, lastItemRef still have the old addToFeed
function reference. You should pass the addToFeed
in lastItemRef
useCallback dependency array. By this when ever the component renders, it will have the latest addToFeed
function reference
CodePudding user response:
you can access val
but the default value of val
is equal to empty string''
try to change the default value to another value to see it
const [val, setVal] = useState("default val");