Tutorial React Native Auth - #4 - Membuat Custom Context Authentikasi React Native

Artikel ini merupakan series dari Tutorial Authentication Dengan React Native dan Laravel Sanctum, disini kita akan membuat sebuah custom context authentikasi pada project kita

Rafi Taufiqurrahman
Dipublish 19/07/2025

Membuat Custom Context Authentikasi React Native

Pada artikel kali ini kita akan membuat sebuah context untuk autentikasi user, silahkan teman-teman buat folder baru dengan nama context, kemudian di dalam folder tersebut buat file baru dengan nama AuthContext.tsx. Kemudian masukkan kode berikut ini:

AuthContext.tsx
import api from "@/api";
import { User } from "@/types/user";
import AsyncStorage from '@react-native-async-storage/async-storage';
import { router } from "expo-router";
import { createContext, useEffect, useState } from "react";

// define type auth context
type AuthContextType = {
  user: User | null;
  isLoading: boolean;
  fetchUser: () => Promise<void>;
  handleRegister: (name: string, email: string, password: string) => Promise<void>;
  handleLogin: (email: string, password: string) => Promise<void>;
  handleLogout: () => Promise<void>;
};

// define context object
export const AuthContext = createContext<AuthContextType>({
    user: null,
    isLoading: false,
    fetchUser: async () => {},
    handleRegister: async () => {},
    handleLogin: async () => {},
    handleLogout: async () => {},
})

export const AuthProvider = ({ children } : {children: React.ReactNode}) => {
    // define state user
    const [user, setUser] = useState<User | null>(null);
    // define state loading
    const [isLoading, setIsLoading] = useState(true);

    // define method fetchUser
    const fetchUser = async () => {
        try{
            // hit api profile
            const response = await api.get('/profile');
            // update state user with response api
            setUser(response.data.user);
        }catch{
            // update state user to null
            setUser(null);
        }finally{
            // update state is loading to false
            setIsLoading(false);
        }
    }

    // define method register
    const handleRegister = async (name: string, email: string, password: string) => {
        // hit api register
        const response = await api.post('/register', { name, email, password});
        // get token user
        const token = response.data.access_token;
        // save token
        await AsyncStorage.setItem('access_token', token);
        // set token to headers authorization
        api.defaults.headers.common['Authorization'] = `Bearer ${token}`;
        // call method fetch user
        await fetchUser();
        // push to dashboard screen
        router.replace('/(home)/dashboard')
    }

    // define method login
    const handleLogin = async (email: string, password: string) => {
        try{
            // hit api login
            const response = await api.post('/login', {email, password})
            // get token user
            const token = response.data.access_token;
            // save token
            await AsyncStorage.setItem('access_token', token);
            // set token to headers authorization
            api.defaults.headers.common['Authorization'] = `Bearer ${token}`;
            // call method fetch user
            await fetchUser();
            // push to dashboard screen
            router.replace('/(home)/dashboard')
        }catch(error){
            throw error;
        }
    }

    // define method logout
    const handleLogout = async () => {
        // hit api logout
        await api.post('/logout');
        // remove token user
        await AsyncStorage.removeItem('access_token');
        // update state user to null
        setUser(null);
        // push to login screen
        router.replace('/(auth)/login')
    }

    // call method fetch user using useEffect hooks
    useEffect(() => {
        // define method to check authentication
        const checkAuth = async () => {
            try{
                // get access_token user
                const token = await AsyncStorage.getItem('access_token');

                if(token){
                    api.defaults.headers.common['Authorization'] = `Bearer ${token}`;
                    await fetchUser();
                }else{
                    setIsLoading(false);
                }
            }catch{
                setIsLoading(false);
            }
        }

        checkAuth();
    }, [])

    return (
        <AuthContext.Provider value={{ fetchUser, user, isLoading, handleRegister, handleLogin, handleLogout }}>
          {children}
        </AuthContext.Provider>
    );
}

Pertama-tama, kita melakukan import beberapa module yang kita butuhkan, seperti:

  • api: konfigurasi axios untuk mengakses API kita.
  • User: tipe data user.
  • AsyncStorage: digunakan untuk menyimpan token autentikasi secara lokal.
  • router: untuk melakukan navigasi antar halaman menggunakan expo-router.
  • Beberapa hooks bawaan dari React seperti createContext, useEffect, dan useState.

Mendefinisikan Tipe Context

Selanjutnya kita mendefinisikan struktur tipe data yang akan digunakan oleh AuthContext.

AuthContext.tsx
type AuthContextType = {
  user: User | null;
  isLoading: boolean;
  fetchUser: () => Promise<void>;
  handleRegister: (name: string, email: string, password: string) => Promise<void>;
  handleLogin: (email: string, password: string) => Promise<void>;
  handleLogout: () => Promise<void>;
};

Pada kode diatas, kita mendefinisikan beberapa tipe data context yang akan menyimpan data user, status isLoading, serta beberapa method yang akan kita buat didalam context seperti fetchUser, handleRegister, handleLogin dan handleLogout.

Membuat dan Mengekspor Context

Lalu kita buat context-nya menggunakan createContext, dan langsung beri nilai default agar tidak terjadi error saat digunakan sebelum AuthProvider terpasang.

AuthContext.tsx
export const AuthContext = createContext<AuthContextType>({
  user: null,
  isLoading: false,
  fetchUser: async () => {},
  handleRegister: async () => {},
  handleLogin: async () => {},
  handleLogout: async () => {},
});

Membuat Komponen AuthProvider

Disini kita akan membuat sebuah komponen baru bernama AuthProvider yang akan digunakan untuk membungkus seluruh aplikasi kita. Komponen ini akan menyediakan data user dan fungsi autentikasi ke seluruh component anak di dalamnya.

AuthContext.tsx
export const AuthProvider = ({ children } : {children: React.ReactNode}) => {

State User dan Loading

Dalam AuthProvider, kita mendefinisikan dua state:

  • user: menyimpan data user yang sedang login.
  • isLoading: penanda bahwa proses autentikasi sedang berlangsung.
AuthContext.tsx
const [user, setUser] = useState<User | null>(null);
const [isLoading, setIsLoading] = useState(true);

Method fetchUser

Method ini digunakan untuk mengambil data profil user yang sedang login.

AuthContext.tsx
const fetchUser = async () => {
  try {
    const response = await api.get('/profile');
    setUser(response.data.user);
  } catch {
    setUser(null);
  } finally {
    setIsLoading(false);
  }
}

Jika API berhasil diakses, maka data user akan disimpan. Jika gagal (misalnya token tidak valid), maka user akan diset ke null. Terakhir, kita pastikan isLoading akan di-set false.

Method handleRegister

Digunakan untuk mendaftarkan user baru.

AuthContext.tsx
const handleRegister = async (name: string, email: string, password: string) => {
  const response = await api.post('/register', { name, email, password });
  const token = response.data.access_token;
  await AsyncStorage.setItem('access_token', token);
  api.defaults.headers.common['Authorization'] = `Bearer ${token}`;
  await fetchUser();
  router.replace('/(home)/dashboard');
}

Setelah berhasil register:

  • Token disimpan ke AsyncStorage
  • Token diset ke header Authorization
  • Data user diambil ulang menggunakan fetchUser
  • User diarahkan ke halaman dashboard

Method handleLogin

Digunakan untuk login user yang sudah terdaftar.

AuthContext.tsx
const handleLogin = async (email: string, password: string) => {
  try {
    const response = await api.post('/login', { email, password });
    const token = response.data.access_token;
    await AsyncStorage.setItem('access_token', token);
    api.defaults.headers.common['Authorization'] = `Bearer ${token}`;
    await fetchUser();
    router.replace('/(home)/dashboard');
  } catch (error) {
    throw error;
  }
}

Alurnya hampir sama seperti handleRegister, namun di sini kita menangani error yang dilempar dari API jika login gagal.

Method handleLogout

Method ini digunakan untuk logout user yang sedang aktif.

AuthContext.tsx
const handleLogout = async () => {
  await api.post('/logout');
  await AsyncStorage.removeItem('access_token');
  setUser(null);
  router.replace('/(auth)/login');
}

Saat logout:

  • Token dihapus dari penyimpanan lokal
  • User dihapus dari state
  • Aplikasi diarahkan kembali ke halaman login

Mengecek Autentikasi Saat Aplikasi Dimuat

Kita ingin memastikan bahwa jika user memiliki token tersimpan, maka data user akan langsung dimuat saat aplikasi dibuka, disini kita menggunakan hooks useEffect.

AuthContext.tsx
useEffect(() => {
  const checkAuth = async () => {
    try {
      const token = await AsyncStorage.getItem('access_token');
      if (token) {
        api.defaults.headers.common['Authorization'] = `Bearer ${token}`;
        await fetchUser();
      } else {
        setIsLoading(false);
      }
    } catch {
      setIsLoading(false);
    }
  }

  checkAuth();
}, []);

Terakhir, kita kembalikan provider dan berikan semua method dan data yang sudah kita buat.

AuthContext.tsx
return (
  <AuthContext.Provider
    value={{ fetchUser, user, isLoading, handleRegister, handleLogin, handleLogout }}
  >
    {children}
  </AuthContext.Provider>
);

Membuat Custom Hook untuk Mengakses Context

Agar kita lebih mudah dalam menggunakan context autentikasi yang kita buat sebelumnya di seluruh komponen aplikasi, kita bisa membuat sebuah custom hook bernama useAuth. Silakan teman-teman buat folder baru dengan nama hooks, lalu di dalam folder tersebut buat file baru dengan nama useAuth.ts, dan masukkan kode berikut:

useAuth.ts
import { AuthContext } from '@/context/AuthContext';
import { useContext } from 'react';

export const useAuth = () => useContext(AuthContext);

Pada kode di atas :

  • Kita mengimpor AuthContext dari file AuthContext.tsx yang sebelumnya telah kita buat.
  • Kita juga menggunakan useContext dari React, yang berfungsi untuk mengakses isi dari context.
useAuth.ts
import { AuthContext } from '@/context/AuthContext';
import { useContext } from 'react';

Kemudian kita membuat sebuah fungsi useAuth, yaitu custom hook yang akan mengembalikan isi dari AuthContext.

useAuth.ts
export const useAuth = () => useContext(AuthContext);

Dengan adanya custom hook ini, kita tidak perlu lagi mengimpor dan menggunakan useContext(AuthContext) secara manual di setiap komponen. Cukup panggil useAuth() saja, dan kita sudah bisa mengakses:

  • user
  • isLoading
  • handleLogin()
  • handleRegister()
  • handleLogout()
  • fetchUser()

Artikel Lainnya

Beberapa artikel rekomendasi lainnya untuk menambah pengetahuan.

1
Belajar Typescript Dasar - #2 - Membuat Project Typescript
Artikel ini merupakan series dari Belajar Typescript Dasar, disini kita akan belajar membuat project typescript dan menjalankannya.
2
Tutorial Inertia Roles & Permissions - #7 - Membuat Share Data Global Inertia
Artikel ini merupakan series dari Tutorial Laravel Inertia Roles & Permissions, disini kita akan belajar membuat sebuah data yang dapat diakses di semua halaman menggunakan inertia.
3
Tutorial Inertia Roles & Permissions - #10 - Membuat Module Dashboard Dengan Inertia React
Artikel ini merupakan series dari Tutorial Laravel Inertia Roles & Permissions, disini kita akan membuat sebuah module dashboard dengan inertia react.
4
Tutorial Laravel Livewire - #6 - Memanfaatkan Salah Satu Magic Laravel Yaitu Eloquent Accessor
Artikel ini merupakan series dari Tutorial Laravel Livewire Study Case Point Of Sales, disini kita akan mengenal salah satu magic laravel yang sangat powerfull yaitu laravel accessor.
5
Tutorial Inertia Roles & Permissions - #6 - Membuat Relasi Antar Tabel Menggunakan Laravel Eloquent Relationship
Artikel ini merupakan series dari Tutorial Laravel Inertia Roles & Permissions, disini kita akan membuat relasi antar tabel menggunakan laravel eloquent relationship.
6
Tutorial Laravel Rest API - #4 - Membuat Module Login
Artikel ini merupakan series dari Tutorial Authentication Dengan Laravel Sanctum dan Unit Testing, disini kita belajar membuat module login selain membuat rest api kita juga menuliskan sebuah unit test untuk module tersebut.

JurnalKoding

Mulai asah skill dengan berbagai macam teknologi - teknologi terbaru seperti Laravel, React, Vue, Inertia, Tailwind CSS, dan masih banyak lagi.

© 2025 JurnalKoding, Inc. All rights reserved.