reactjsreact-nativesqliteexpo

I tips with this error from sqlite and expo?


I am trying to connect local storage using SQLite for my APK, but I keep getting errors like this:

ERROR: Db not initialized: [TypeError: SQLite.openDatabase is not a function (it is undefined)]

I have followed the documentation (https://docs.expo.dev/versions/latest/sdk/sqlite/) and installed the dependency, but I am still getting errors. Can someone help me fix this?

 import React, { useState, useEffect } from 'react';
import {
  Text,
  View,
  StatusBar,
  StyleSheet,
  TextInput,
  Pressable,
  Keyboard,
  ScrollView,
  KeyboardAvoidingView,
  Platform,
  Alert,
  ActivityIndicator
} from 'react-native';
import { SafeAreaView } from 'react-native-safe-area-context';
import GenderButton from '../components/GenderButton';

import * as SQLite from 'expo-sqlite';


const openDatabase = () => {
  const db = SQLite.openDatabase('RegisterSQL.db');
  return db;
};


const createTables = (db) => {
  db.transaction(tx => {
    tx.executeSql(
      `CREATE TABLE IF NOT EXISTS users (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        firstName TEXT NOT NULL,
        lastName TEXT NOT NULL,
        username TEXT NOT NULL,
        gender TEXT NOT NULL,
        email TEXT UNIQUE NOT NULL,
        password TEXT NOT NULL,
        createdAt DATETIME DEFAULT CURRENT_TIMESTAMP
      )`
    );
  });
};

export default function RegisterScreen() {
  const [formData, setFormData] = useState({
    firstName: '',
    lastName: '',
    username: '',
    email: '',
    password: '',
    confirmPassword: '',
    gender: 'Neutral'
  });
  const [db, setDb] = useState(null);
  const [loading, setLoading] = useState(false);
  const [dbReady, setDbReady] = useState(false);


  useEffect(() => {
    let isMounted = true;

    const initDB = () => {
      try {
        const database = openDatabase();
        createTables(database);
        
        if (isMounted) {
          setDb(database);
          setDbReady(true);
        }
      } catch (error) {
        console.error('Db not initilaizd:', error);
        if (isMounted) {
          Alert.alert(
            'Error', 
            'DB mistake, storage wont work.'
          );
        }
      }
    };

    initDB();

    return () => {
      isMounted = false;
      if (db) {
        db.close().catch(e => console.warn('BP not opening:', e));
      }
    };
  }, []);

  const handleGenderChange = (gender) => {
    setFormData({...formData, gender});
  };

  const handleRegister = async () => {
    if (loading) return;


    if (!formData.firstName || !formData.lastName || !formData.username || 
        !formData.email || !formData.password || !formData.confirmPassword) {
      Alert.alert('Error', 'Fill out the form');
      return;
    }

    if (formData.password !== formData.confirmPassword) {
      Alert.alert('Greška', 'Passwords must match');
      return;
    }

    if (!dbReady) {
      Alert.alert('Error', 'BP not ready.');
      return;
    }

    setLoading(true);

    try {
      db.transaction(async (tx) => {
        await tx.executeSql(
          `INSERT INTO users 
          (firstName, lastName, username, gender, email, password) 
          VALUES (?, ?, ?, ?, ?, ?)`,
          [
            formData.firstName,
            formData.lastName,
            formData.username,
            formData.gender,
            formData.email,
            formData.password
          ]
        );
      });

      Alert.alert('Registered', 'Works!');
      // Resetiranje forme
      setFormData({
        firstName: '',
        lastName: '',
        username: '',
        email: '',
        password: '',
        confirmPassword: '',
        gender: 'Neutral'
      });
    } catch (error) {
      console.error('Wrong input:', error);
      Alert.alert(
        'Greška', 
        error.message.includes('UNIQUE') 
          ? 'Email already exists' 
          : 'Register error'
      );
    } finally {
      setLoading(false);
    }
  };

  return (
    <>
      <StatusBar barStyle="dark-content" backgroundColor="#FAFAFA" />
      <SafeAreaView style={styles.safeArea} edges={['top']}>
        <KeyboardAvoidingView
          behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
          style={{ flex: 1 }}
          keyboardVerticalOffset={Platform.OS === 'ios' ? 74 : 0}
        >
          <ScrollView
            contentContainerStyle={{ flexGrow: 1 }}
            keyboardShouldPersistTaps="handled"
          >
            <Pressable onPress={() => Keyboard.dismiss()} style={{ flex: 1 }}>
              <View style={styles.textConatiner}>
                <Text style={styles.headerText}>Slika</Text>
              </View>
              
              <View style={styles.loginContainer}>
                <View style={styles.doubleInputContainer}>
                  <View style={styles.doubleInput}>
                    <TextInput
                      placeholder="First Name"
                      placeholderTextColor="#A0A0A0"
                      style={styles.inputText}
                      value={formData.firstName}
                      onChangeText={(text) => setFormData({...formData, firstName: text})}
                    />
                  </View>
                  <View style={styles.doubleInput}>
                    <TextInput
                      placeholder="Last Name"
                      placeholderTextColor="#A0A0A0"
                      style={styles.inputText}
                      value={formData.lastName}
                      onChangeText={(text) => setFormData({...formData, lastName: text})}
                    />
                  </View>
                </View>

                <View style={styles.doubleInputContainer}>
                  <View style={styles.doubleInput}>
                    <TextInput
                      placeholder="Username"
                      placeholderTextColor="#A0A0A0"
                      style={styles.inputText}
                      value={formData.username}
                      onChangeText={(text) => setFormData({...formData, username: text})}
                    />
                  </View>
                  <GenderButton onGenderChange={handleGenderChange} />
                </View>

                <View style={styles.inputContainer}>
                  <View style={styles.singleInput}>
                    <TextInput
                      placeholder="Email"
                      placeholderTextColor="#A0A0A0"
                      style={styles.inputText}
                      keyboardType="email-address"
                      autoCapitalize="none"
                      value={formData.email}
                      onChangeText={(text) => setFormData({...formData, email: text})}
                    />
                  </View>
                </View>

                <View style={styles.inputContainer}>
                  <View style={styles.singleInput}>
                    <TextInput
                      placeholder="Password"
                      placeholderTextColor="#A0A0A0"
                      style={styles.inputText}
                      secureTextEntry
                      value={formData.password}
                      onChangeText={(text) => setFormData({...formData, password: text})}
                    />
                  </View>
                </View>

                <View style={styles.inputContainer}>
                  <View style={styles.singleInput}>
                    <TextInput
                      placeholder="Confirm Password"
                      placeholderTextColor="#A0A0A0"
                      style={styles.inputText}
                      secureTextEntry
                      value={formData.confirmPassword}
                      onChangeText={(text) => setFormData({...formData, confirmPassword: text})}
                    />
                  </View>
                </View>

                <Pressable 
                  style={[styles.registerButton, loading && styles.disabledButton]}
                  onPress={handleRegister}
                  disabled={loading}
                >
                  {loading ? (
                    <ActivityIndicator color="white" />
                  ) : (
                    <Text style={styles.registerButtonText}>Register</Text>
                  )}
                </Pressable>

                <View style={styles.termsContainer}>
                  <Text style={styles.termsText}>TOS</Text>

                </View>
              </View>
            </Pressable>
          </ScrollView>
        </KeyboardAvoidingView>
      </SafeAreaView>
    </>
  );
}
const styles = StyleSheet.create({
  safeArea: {
    flex: 1,
    backgroundColor: '#FAFAFA',
  },
  textConatiner: {
    borderColor: '#E0E0E0',
    borderTopLeftRadius: 100,
    borderBottomLeftRadius: 100,
    backgroundColor: '#F0F0F0',
    borderWidth: 1,
    marginTop: '15%',
    marginLeft: '7%',
    paddingLeft: '5%'
  },
  headerText: {
    textAlign: 'justify',
    fontSize: 52,
    color: 'grey',
  },
  loginContainer: {
    flexGrow: 1,
    backgroundColor: '#F0F0F0',
    borderTopWidth: 1.2,
    borderLeftWidth: 0.8,
    borderRightWidth: 0.8,
    borderColor: '#E0E0E0',
    alignItems: 'center',
    borderTopLeftRadius: 40,
    borderTopRightRadius: 40,
    marginTop: '10%',
    paddingVertical: 24,
    paddingBottom: 40,
  },
  inputContainer: {
    width: '86%',
    marginTop: 12,
  },
  singleInput: {
    borderColor: '#D0D0D0',
    borderWidth: 1.2,
    backgroundColor: '#E8E8E8',
    height: 48,
    justifyContent: 'center',
    paddingLeft: 12,
    borderRadius: 4, 
  },
  doubleInputContainer: {
    flexDirection: 'row',
    marginTop: 12,
    gap: 12,
    width: '86%',
  },
  doubleInput: {
    flex: 1,
    borderColor: '#D0D0D0',
    borderWidth: 1.2,
    backgroundColor: '#E8E8E8',
    height: 48,
    justifyContent: 'center',
    paddingLeft: 12,
    borderRadius: 4, 
  },
  inputText: {
    color: '#333333',
    fontSize: 16,
  },
  registerButton: {
    backgroundColor: '#FF715B',
    padding: 15,
    borderRadius: 8,
    marginTop: 20,
    width: '86%',
    alignItems: 'center',
    justifyContent: 'center',
    height: 50,
  },
  disabledButton: {
    backgroundColor: '#CCCCCC',
  },
  registerButtonText: {
    color: 'white',
    fontWeight: 'bold',
    fontSize: 16,
  },
  termsContainer: {
    marginTop: 20,
    alignItems: 'center',
  },
  termsText: {
    color: '#4c5b5c',
    marginVertical: 5,
  }
});`enter code here`

Solution

  • You're using SQLite.openDatabase, but that method doesn't exist.

    From the docs it looks like you need to use either SQLite.openDatabaseSync or SQLite.openDatabaseAsync instead.

    https://docs.expo.dev/versions/latest/sdk/sqlite/#sqliteopendatabaseasyncdatabasename-options-directory