Mengkombinasikan Tanstack Query dengan React Context

05 April 2025
ยท
3 min read

Sebagai contoh, kita memiliki sebuah custom hook bernama useCurrentUserQuery yang berfungsi untuk mengambil data user yang sedang login menggunakan Tanstack Query

function useCurrentUserQuery() {
  return useQuery({
    queryKey: ["user"],
    queryFn: () => fetchCurrentUser(),
  });
}

Seperti biasa, kita bisa menggunakan custom hook tersebut dengan cara seperti berikut.

function UserNameDisplay() {
  const query = useCurrentUserQuery();
 
  if (query.isPending) {
    return <div>Loading...</div>;
  }
 
  if (query.isError) {
    return <div>Error: {query.error}</div>;
  }
 
  return <div>User: {query.data.username}</div>;
}

Umumnya ini bukan masalah, tetapi untuk data-data yang bersifat global seperti data user, ini kurang optimal. karena setiap kali kita mengaksesnya, kita perlu melakukan pengecekan terhadap isPending dan isError untuk memastikan data tersebut tersedia.

Adakah cara yang lebih baik ? dikasus ini kita bisa menyederhanakannya dengan menggunakan React Context.

Membuat Context dan Provider

Pertama, kita buat sebuah context bernama CurrentUserContext dan provider-nya. Provider ini akan mengambil data initial dengan useCurrentUserQuery dan menyimpannya ke dalam context.

type User = {
  username: string;
};
 
// Membuat context
const CurrentUserContext = React.createContext<User | null>(null);
 
// Membuat provider
export const CurrentUserContextProvider = ({
  children,
}: {
  children: React.ReactNode;
}) => {
  const query = useCurrentUserQuery();
 
  if (query.isPending) {
    return <div>Loading...</div>;
  }
 
  if (query.isError) {
    return <div>Error: {query.error}</div>;
  }
 
  return (
    // pass initial data ke dalam context
    <CurrentUserContext.Provider value={query.data}>
      {children}
    </CurrentUserContext.Provider>
  );
};

Memasang Provider di Root Component

Setelah membuat provider, kita perlu memasangnya di root component, agar data dari provider tersebut bisa diakses disemua component tree.

// contoh root component di next.js
export default function App({ Component, pageProps }: AppProps) {
  return (
    <CurrentUserContextProvider>
      <Component {...pageProps} />
    </CurrentUserContextProvider>
  );
}

Membuat Hook untuk Mengakses Data User

Setelah provider terpasang, kita bisa membuat sebuah hook untuk mengakses data user yang sedang login dari context yang telah kita buat sebelumnya.

export const useCurrentUserContext = () => {
  const currentUser = React.useContext(CurrentUserContext);
  if (!currentUser) {
    throw new Error("CurrentUserContext: No value provided");
  }
 
  return currentUser;
};

Mengakses Data User dari Component

Setelah provider terpasang, kita dapat mengambil data user yang sedang login tanpa perlu memeriksa status isPending dan isError setiap kali data digunakan. Berikut adalah contoh penggunaannya:

function UserNameDisplay() {
  const data = useCurrentUserContext();
  return <div>User: {data.username}</div>;
}

State Syncing ?

Untuk yang sudah berpengalaman dengan Tanstack Query, mungkin ini terlihat seperti "state syncing" dimana hal ini kurang direkomendasikan karena berpotensi "out of sync" antara data yang ada di context dan data yang ada di Tanstack Query.

Tetapi contoh diatas bukan state syncing, karena source of truth tetap dari Tanstack Query dan context hanya sebagai "distributor" datanya saja.

Kesimpulan

Dengan menggunakan React Context kita bisa menyederhanakan beberapa kasus dengan mudah dan tanpa library tambahan.