使用 GraphQL 获取的 useEffect 无限循环

发布于 2025-01-18 19:16:12 字数 2236 浏览 2 评论 0原文

我正在编写一个简单的 React hook,它从 GraphQL 端点获取一些数据,将结果存储在一个状态中,并在获取数据时返回 [fetched-data, true][null, false] 当没有数据时,您可以在像 const [data, returned] = useGraphql({ query, Variables }); 这样的组件中使用它。返回已加载?数据:'正在加载'

我遇到的问题是,如果我声明参数对象的可选变量属性,则挂钩会导致无限的 useEffect 循环。如果我省略变量参数,一切都会正常。

export default function useGraphql({ query, variables, token }: QueryArgs) {
    const [data, setData] = useState(null)

    const fetchData = useCallback(async () => {
        const init: RequestInit = {
            method: "POST",
            headers: {
                [token && 'Authorization']: token && `bearer ${token}`,
                "Content-Type": "application/json",
                "Accept": "application/json"
            },
            body: JSON.stringify({
                query, variables
            })
        }

        try {
            const response: Response = await fetch('/graphql', init)

            const parsed = await response.json()

            setData(parsed.data)
        } catch (error) {
            console.log(error)

            setData(null)
        }
    }, [query, variables, token]) // if I remove variables from the array here, this doesn't cause a loop anymore

    useEffect(() => {
        let mounted = true

        if (mounted) {
            fetchData()
        }

        return () => {
            mounted = false

            setData(null)
        }
    }, [fetchData])

    if (data) {
        for (const prop in data) {
            return [data[prop], true]

            break;
        }
    }

    return [null, false]
} 

当然,我在组件中使用这样的钩子:

const [data, loaded] = useGraphql({ 
        query: `query ($email: String!) {
            singleUser(email: $email) {
                username
                email
            }
        }`,
        variables: {
            email: "user1@project" // if I put variables like this, the loop occurs. If I hardcode the variables in the query, there is no loop.
        }
    })

    return <span> {loaded ? data.email : 'loading'} </span>

我真的不明白为什么放置变量会导致无限的重新渲染。 variables 参数如何改变 fetchData 函数?

I am writing a simple react hook that fetches some data form a GraphQL endpoint, stores the result in a state and returns [fetched-data, true] when the data is fetched or [null, false] when there is no data so you can use it in components like const [data, loaded] = useGraphql({ query, variables }); return loaded ? data : 'loading'.

The problem I am experiencing is that if I declare the optional variables property of the argument object, the hook causes an infinite useEffect loop. If I omit the variables argument, everything works fine.

export default function useGraphql({ query, variables, token }: QueryArgs) {
    const [data, setData] = useState(null)

    const fetchData = useCallback(async () => {
        const init: RequestInit = {
            method: "POST",
            headers: {
                [token && 'Authorization']: token && `bearer ${token}`,
                "Content-Type": "application/json",
                "Accept": "application/json"
            },
            body: JSON.stringify({
                query, variables
            })
        }

        try {
            const response: Response = await fetch('/graphql', init)

            const parsed = await response.json()

            setData(parsed.data)
        } catch (error) {
            console.log(error)

            setData(null)
        }
    }, [query, variables, token]) // if I remove variables from the array here, this doesn't cause a loop anymore

    useEffect(() => {
        let mounted = true

        if (mounted) {
            fetchData()
        }

        return () => {
            mounted = false

            setData(null)
        }
    }, [fetchData])

    if (data) {
        for (const prop in data) {
            return [data[prop], true]

            break;
        }
    }

    return [null, false]
} 

of course I am using this hook like this in a component:

const [data, loaded] = useGraphql({ 
        query: `query ($email: String!) {
            singleUser(email: $email) {
                username
                email
            }
        }`,
        variables: {
            email: "user1@project" // if I put variables like this, the loop occurs. If I hardcode the variables in the query, there is no loop.
        }
    })

    return <span> {loaded ? data.email : 'loading'} </span>

I really don't understand why putting variables is causing infinite rerenders. How is variables argument changing the fetchData function?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

撑一把青伞 2025-01-25 19:16:12

我现在想出了以下解决方案:

我不传递普通变量对象,而是使用以下代码检查它是否已更改并将结果作为字符串返回。

function updateObj(obj: object): string {
    let object: string = JSON.stringify(obj)

    if (object !== JSON.stringify(obj)) {
        object = JSON.stringify(obj)
    }

    return object
}

所以在我的 useGraphql 钩子中,我像这样使用它:

const updatedVariables = updateObj(variables) 

它正在完成它的工作。我尝试返回一个对象而不是字符串化对象,但解析结果(使用 JSON.parse())仍然导致循环

I came up with the following solution for now:

instead of passing the plain variables object, I check if it has changed with the following code and return the result as a string.

function updateObj(obj: object): string {
    let object: string = JSON.stringify(obj)

    if (object !== JSON.stringify(obj)) {
        object = JSON.stringify(obj)
    }

    return object
}

so in my useGraphql hook I use it like:

const updatedVariables = updateObj(variables) 

and it is doing its job. I've tried to return an object instead of a stringified one but then the parsed result (with JSON.parse()) is still causing the loop

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文