Home > Enterprise >  Cannot access value of state inside function body that's inside component
Cannot access value of state inside function body that's inside component

Time:05-09

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");

playground for your code

  • Related