我想出了我的定制react 钩子来处理上库,我不知道到处使用这个钩子是不是最好的做法,因为我每次使用它时都要处理isLoading个钩子.

import { useEffect, useState } from 'react'
import { useAuth } from '@clerk/nextjs'
import { createClient } from '@supabase/supabase-js'
import { SupabaseClient } from '@supabase/supabase-js'

const createSupabaseClient = (token: string) => {
  if (!process.env.NEXT_PUBLIC_SUPABASE_URL) {
    throw new Error('NEXT_PUBLIC_SUPABASE_URL is not defined')
  }
  if (!process.env.NEXT_PUBLIC_SUPABASE_KEY) {
    throw new Error('NEXT_PUBLIC_SUPABASE_KEY is not defined')
  }

  return createClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL,
    process.env.NEXT_PUBLIC_SUPABASE_KEY,
    {
      global: {
        headers: {
          Authorization: `Bearer ${token}`,
        },
      },
    },
  )
}

export const useSupabase = () => {
  const { getToken } = useAuth()
  const [supabase, setSupabase] = useState<SupabaseClient>()
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState()

  useEffect(() => {
    const fetchTokenAndInitializeClient = async () => {
      try {
        const token = await getToken({ template: 'supabase' })
        if (!token) {
          throw new Error('No token found')
        }
        const supabase = createSupabaseClient(token)
        setSupabase(supabase)
        setLoading(false)
      } catch (err) {
        setError(err as any)
        setLoading(false)
      }
    }

    fetchTokenAndInitializeClient()
  }, [getToken])

  return { supabase, loading, error }
}

推荐答案

这种方法的问题是,每次您呼叫useSupabase时,useEffect都会运行,因为生命周期将从您放入的每个组件开始.

你说得对,我们应该在某个地方处理这件事.

解决这个问题的一个好方法是创建一个拥有React.Context个人的Provider .

const SupabaseContext = useContext({
  supabase: undefined,
  loading: false,
  error: undefined
})

export const SupabaseProvider({ children }) {
  const { getToken } = useAuth()

  const [supabase, setSupabase] = useState<SupabaseClient>()
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState()

  useEffect(() => {
    const fetchTokenAndInitializeClient = async () => {
      try {
        const token = await getToken({ template: 'supabase' })
        if (!token) {
          throw new Error('No token found')
        }
        const supabase = createSupabaseClient(token)
        setSupabase(supabase)
      } catch (err) {
        setError(err as any)
      } finally {
        setLoading(false)
      }
    }

    fetchTokenAndInitializeClient()
  }, [getToken])

  return (
    <SupabaseContext.Provider value={{ supabase, loading, error }}>
      {children}
    </SupabaseContext.Provider>
  )
}

现在,您可以将其包装在应用程序的顶层,如下所示:

const App = () => (
  <SupabaseProvider>
    ...
  </SupabaseProvider>
)

在下面的组件中,您可以使用钩子访问supabase(以及它的加载和错误状态):

const { supabase, loading, error } = useContext(SupabaseContext);

如果您不想担心所有子组件中的loading状态,则可以在应用程序中使用更高级别的Guard语句,以便仅在loading为False时才呈现子组件.

下面是一个在你SupabaseProvider岁时在顶层做到这一点的例子:

return (
  <SupabaseContext.Provider value={{ supabase, loading, error }}>
    {isloading ? <LoadingSupabase /> : children}
  </SupabaseContext.Provider>
)

Reactjs相关问答推荐

useTranslation不会在languageChanged上重新呈现组件

为多租户SSO登录配置Azure AD应用程序

react -无法获取函数的最新参数值

无法在下一个标头上使用 React hooks

错误:无法获取 RSC 负载.返回浏览器导航

验证 Yup 中的对象项

React-router-dom的链接不改变路由(ReactRouter6)

useMemo 依赖项的行为

React Js和Firestore中如何将当前ID与集合中的ID查询以仅显示具有相似字段和值的文档-第二部分

redux 工具包使用中间件构建器函数时,必须返回一个中间件数组

根据其中的值不同地react setState 更新状态

在按钮单击中将动态参数传递给 React Query

如何在悬停时更改 MUI 卡内容

在 React 的父级中多次调用子级时从子级获取数据到父级

如何在 Cypress E2E 的站点上测试react 组件?

如何使用 babel 将 SVG 转换为 React 组件?

无法有条件地更新useEffect中的setState

多次响应获取发送请求

将 C# Razor 条件块转换为 React.js 代码

根据计算 ReactJs 更新输入字段