Лучшая практика интеграции клерка с supabase

Я придумал свой пользовательский хук реагирования для работы с супабазой, я не знаю, будет ли использование этого хука везде лучшей практикой, поскольку мне приходится иметь дело с 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 }
}
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
2
0
92
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Проблема с этим подходом заключается в том, что каждый раз, когда вы вызываете useSupabase, useEffect будет запускаться, потому что жизненный цикл будет запускаться для каждого компонента, в который вы поместите это.

Вы правы, что мы должны иметь дело с этим где-то.

Хороший способ решить эту проблему — создать провайдера с помощью React.Context.

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 во всех ваших дочерних компонентах, вы можете использовать оператор защиты выше в своем приложении, чтобы отображать дочерний компонент только в том случае, если loading имеет значение false.

Вот пример того, как это сделать на верхнем уровне в вашем SupabaseProvider:

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

Что бы вы порекомендовали для обновления токена клерка?

aaronmbmorse 01.05.2023 22:44

Вам просто нужно обновить логику useEffect. Я думаю, в конце концов вы захотите сохранить клиента в состоянии провайдера и инициализировать клиент при монтировании компонента (при условии, что токен существует), а затем в отдельном useEffect, который прослушивает изменения токена, обновите существующий клиент (в состоянии) там .

Barry Michael Doyle 01.05.2023 22:56

Другие вопросы по теме