Home > Back-end >  call callback function only once
call callback function only once

Time:12-29

I am working on a fullstack project with ReactJS in front and it has user management.

Some pages are available only if the user is connected, so basically, I am checking it by asking my server, and I am doing it in my NavBar.js component (because it used in every pages).

it looks like something like this:

const Navigation = ({ callback }) => {
    useEffect(() => {
        axios({
            method: "GET",
            withCredentials: true,
            url: process.env.REACT_APP_SERVER   "/user",
        }).then((res) => {
            if (callback) 
                callback(res.data.username);
            setUser(res.data.username);
        }).catch((e) => {
            if (callback)
                callback(null);
        });
    }, [callback])

    return (
        <div>Some navbar stuff</div>
    )
}

export default Navigation;

and inside my other pages, I use my Navigation component like this :

const PublishContent = () => {
    const [loading, setLoading] = useState(true);
    const [user, setUser] = useState(null);

    const handleUserName = e => {
        setUser(e);
        setLoading(false);
    }

    return (
        <div>
            <Navigation callback={handleUserName} />
            {
                !loading && <div>{user ? <div>CONNECTED</div> : <div> NOT CONNECTED</div>} </div>
            }
        </div>
    )
}

export default PublishContent;

My problem is that my handleUserName is called three times, I don't understand why, even if callback is the the dependency list of my UseEffect, it should be constant...

Also, since useState is async, even if the user is logged, the first time my user is undefined.

Do you know how I can solve this problem ? Also, can you tell me if the way I am doing (checking if user is authenticated, sounds weird to you ? Thank you.

CodePudding user response:

Every time handleUserName is called it's going to call setUser and setLoading which both will initiated a re-render. When the PublishContent component re-renders (twice in this instance) it will create a new function and assign it to handleUserName which then gets passed into your Navigation component and into your useEffect, causing your useEffect to re-run since the dependency has changed (new function as a result of re-rendering). To solve your problem you just need to wrap handleUserName in a useCallback like so

const handleUserName = useCallback((e) => {
  setUser(e)
  setLoading(false)
}, [])

You also shouldn't be calling setUser in Navigation. If you need to access it you can pass it down as a prop

const PublishContent = () => {
    const [loading, setLoading] = useState(true);
    const [user, setUser] = useState(null);

    const handleUserName = useCallback(e => {
        setUser(e);
        setLoading(false);
    }, [])

    return (
        <div>
            <Navigation callback={handleUserName} user={user} />
            {
                !loading && <div>{user ? <div>CONNECTED</div> : <div> NOT CONNECTED</div>} </div>
            }
        </div>
    )
}

export default PublishContent;

  • Related