只调用一次回调函数

call callback function only once

我正在做一个前面有 ReactJS 的全栈项目,它有用户管理。

有些页面只有在用户连接时才可用,所以基本上,我通过询问我的服务器来检查它,我在我的 NavBar.js 组件中进行检查(因为它在每个页面中使用)。

看起来像这样:

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;

在我的其他页面中,我使用这样的导航组件:

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;

我的问题是我的handleUserName被调用了3次,我不明白为什么,即使callback是我的UseEffect的依赖列表,它应该是常数...

此外,由于useState是异步的,即使用户登录了,第一次我的user也是未定义的。

你知道我怎么解决这个问题吗?另外,你能告诉我我正在做的事情吗(检查用户是否已通过身份验证,对你来说听起来很奇怪?谢谢。

每次调用 handleUserName 时,它都会调用 setUser 和 setLoading,它们都会启动重新渲染。当 PublishContent 组件重新呈现(在本例中为两次)时,它将创建一个新函数并将其分配给 handleUserName,然后将其传递到您的 Navigation 组件和您的 useEffect,导致您的 useEffect 重新 运行 自依赖性已更改(重新渲染后的新功能)。要解决您的问题,您只需要像这样

将 handleUserName 包装在 useCallback 中

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

您也不应该在导航中调用 setUser。如果你需要访问它,你可以将它作为 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;