React Native / Supabase Auth React Native-д

Supabase Auth React Native-д

Өмнөх хичээлд Supabase-г React Native-д холбож сурсан. Одоо хэрэглэгч бүртгүүлэх, нэвтрэх, гарах бүрэн authentication системийг бүтээнэ. Supabase Auth нь маш хялбар — цөөхөн мөр кодоор бэлэн болно.

Supabase client тохируулга

Эхлээд @supabase/supabase-js болон @supabase/async-storage суулгана. React Native дээр session хадгалахад AsyncStorage шаардлагатай.

bash
npx expo install @supabase/supabase-js @react-native-async-storage/async-storage

Дараа нь lib/supabase.ts файл үүсгэж client-г тохируулна:

typescript
import { createClient } from "@supabase/supabase-js";
import AsyncStorage from "@react-native-async-storage/async-storage";

const SUPABASE_URL = "https://your-project.supabase.co";
const SUPABASE_ANON_KEY = "your-anon-key";

export const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY, {
  auth: {
    storage: AsyncStorage,
    autoRefreshToken: true,
    persistSession: true,
    detectSessionInUrl: false,
  },
});

detectSessionInUrl: false — React Native дээр URL-based redirect байхгүй тул заавал false болгоно.

Бүртгэл ба нэвтрэх дэлгэц

AuthScreen.tsx нэртэй нэг дэлгэцэнд бүртгэл болон нэвтрэх хоёуланг оруулж болно:

typescript
import { useState } from 'react';
import {
  View,
  Text,
  TextInput,
  TouchableOpacity,
  StyleSheet,
  Alert,
} from 'react-native';
import { supabase } from '../lib/supabase';

export default function AuthScreen() {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [isLogin, setIsLogin] = useState(true);
  const [loading, setLoading] = useState(false);

  async function handleAuth() {
    setLoading(true);
    let error;

    if (isLogin) {
      const result = await supabase.auth.signInWithPassword({ email, password });
      error = result.error;
    } else {
      const result = await supabase.auth.signUp({ email, password });
      error = result.error;
    }

    setLoading(false);

    if (error) {
      Alert.alert('Алдаа', error.message);
    }
  }

  return (
    <View style={styles.container}>
      <Text style={styles.title}>
        {isLogin ? 'Нэвтрэх' : 'Бүртгүүлэх'}
      </Text>

      <TextInput
        style={styles.input}
        placeholder="И-мэйл"
        placeholderTextColor="#475569"
        value={email}
        onChangeText={setEmail}
        keyboardType="email-address"
        autoCapitalize="none"
      />

      <TextInput
        style={styles.input}
        placeholder="Нууц үг"
        placeholderTextColor="#475569"
        value={password}
        onChangeText={setPassword}
        secureTextEntry
      />

      <TouchableOpacity
        style={styles.button}
        onPress={handleAuth}
        disabled={loading}
      >
        <Text style={styles.buttonText}>
          {loading ? 'Ачааллаж байна...' : isLogin ? 'Нэвтрэх' : 'Бүртгүүлэх'}
        </Text>
      </TouchableOpacity>

      <TouchableOpacity onPress={() => setIsLogin(!isLogin)}>
        <Text style={styles.toggle}>
          {isLogin ? 'Шинэ хэрэглэгч? Бүртгүүлэх' : 'Бүртгэлтэй юу? Нэвтрэх'}
        </Text>
      </TouchableOpacity>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    padding: 24,
    backgroundColor: '#0b1120',
  },
  title: {
    fontSize: 28,
    fontWeight: 'bold',
    color: '#f1f5f9',
    marginBottom: 32,
    textAlign: 'center',
  },
  input: {
    backgroundColor: '#0f172a',
    borderWidth: 1,
    borderColor: '#1e293b',
    borderRadius: 8,
    padding: 14,
    color: '#f1f5f9',
    marginBottom: 12,
    fontSize: 16,
  },
  button: {
    backgroundColor: '#22d3ee',
    borderRadius: 8,
    padding: 14,
    alignItems: 'center',
    marginTop: 8,
  },
  buttonText: {
    color: '#0b1120',
    fontWeight: 'bold',
    fontSize: 16,
  },
  toggle: {
    color: '#94a3b8',
    textAlign: 'center',
    marginTop: 20,
    fontSize: 14,
  },
});

Session listener ба navigation

Хэрэглэгч нэвтэрсэн эсэхийг App.tsx-д listener ашиглан хянана. onAuthStateChange event нь автоматаар дуудагдаж, дэлгэцийг шилжүүлнэ:

typescript
import { useEffect, useState } from 'react';
import { Session } from '@supabase/supabase-js';
import { supabase } from './lib/supabase';
import AuthScreen from './screens/AuthScreen';
import HomeScreen from './screens/HomeScreen';

export default function App() {
  const [session, setSession] = useState<Session | null>(null);

  useEffect(() => {
    // Одоогийн session-г авна
    supabase.auth.getSession().then(({ data: { session } }) => {
      setSession(session);
    });

    // Session өөрчлөгдөхийг хянана
    const { data: { subscription } } = supabase.auth.onAuthStateChange(
      (_event, session) => {
        setSession(session);
      }
    );

    return () => subscription.unsubscribe();
  }, []);

  return session ? <HomeScreen session={session} /> : <AuthScreen />;
}

Гарах нь маш энгийн — нэг мөр:

typescript
await supabase.auth.signOut();

Supabase session-г автоматаар устгаж, onAuthStateChange дуудагдан дэлгэц AuthScreen руу буцна.

Дараагийн хичээлд:

Secure Storage — хэрэглэгчийн нууц мэдээллийг (token, нууц үг) утасны аюулгүй хадгалалтад хэрхэн хадгалах талаар сурна. AsyncStorage нь энгийн өгөгдөлд сайн боловч нууц мэдээлэлд тусгай хамгаалалт шаардлагатай.