Supabase, Clerk, React, Vite: Multiple GoTrueClient instances detected in the same browser context

109 views Asked by At

I'm trying to create a very basic app in which I'm using Clerk for Auth and supabase as my db. I've followed the tutorials that I could find and stitched something together which works pretty well except for the console error:

Multiple GoTrueClient instances detected in the same browser context. It is not an error, but this should be avoided as it may produce undefined behavior when used concurrently under the same storage key.

My setup is as follows:

createSupabaseClient.ts

import { createClient } from "@supabase/supabase-js";

const createSupabaseClient = async (supabaseAccessToken: string | null) => {
    const supabase = createClient(
        import.meta.env.VITE_SUPABASE_URL,
        import.meta.env.VITE_SUPABASE_KEY,
        {
            global: { headers: { Authorization: `Bearer ${supabaseAccessToken}` } },
        }
    );

    return supabase;
};

export default createSupabaseClient;

And then I'm using that in VacationTable.tsx

import { useEffect, useState } from "react";
import { useAuth } from "@clerk/clerk-react";
import createSupabaseClient from "./utils/createSupabaseClient";
import { Table } from "antd";

import dayjs from "dayjs";
import relativeTime from "dayjs/plugin/relativeTime";
dayjs.extend(relativeTime);

function VacationTable() {
    const [vacations, setVacations] = useState([]);

    const vacationColumns = [...];

    const { getToken } = useAuth();

    useEffect(() => {
        const fetchVacations = async () => {
            const supabaseAccessToken = await getToken({ template: "supabase" });
            const supabase = await createSupabaseClient(supabaseAccessToken);

            const { data, error } = await supabase.from("vacations").select("*");

            if (error) {
                console.error("Error fetching vacations:", error);
            } else {
                setVacations(data);
            }
        };

        fetchVacations();
    }, [getToken]);

    useEffect(...);

    return (
        <>
            <Table ...></Table>
        </>
    );
}

export default VacationTable;

I've seen 2x somewhat simplar stackoverflow questions. One eluded to it being react rendering twice and the other mentioned a whole Provider setup. TBH I'm very new to React and really just want to keep things simple.

FWIW if I comment out <React.StrictMode> the error disappears - but this seems a bit fishy to me to be the correct solution

Oh and for now I've set Typescript not to be strict while I'm still learning.

1

There are 1 answers

0
somethingElse On

Through the help of ChatGPT and a hint I found this is what solved it for me!!!

import { createClient, SupabaseClient } from "@supabase/supabase-js";

const SUPABASE_URL = import.meta.env.VITE_SUPABASE_URL as string;
const SUPABASE_ANON_KEY = import.meta.env.VITE_SUPABASE_ANON_KEY as string;

let cachedSupabaseClient: SupabaseClient | null = null;
let lastToken: string | null = null;

const createSupabaseClient = async (supabaseAccessToken: string | null) => {
    if (supabaseAccessToken === lastToken && cachedSupabaseClient !== null) {
        return cachedSupabaseClient;
    }

    lastToken = supabaseAccessToken;

    const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY, {
        global: { headers: { Authorization: `Bearer ${supabaseAccessToken}` } },
    });

    cachedSupabaseClient = supabase;

    return supabase;
};

export default createSupabaseClient;

Basically, caching the supabase client and the token and checking them before creating another client. Man I wish this was documented somewhere!