Expo SQLite报错:ReferenceError: Property 'db' doesn't exist 求助
Expo SQLite 打开数据库时出现 ReferenceError: Property 'db' doesn't exist 问题解决
错误信息
在React Native(Expo)项目中使用expo-sqlite打开expenses.db数据库时,触发以下错误:
ReferenceError: Property 'db' doesn't exist, js engine: hermes
错误出现在这段初始化代码:
const db = SQLite.openDatabase({ name: 'expenses.db', location: 'default', });
完整问题代码
import { View, Text, Pressable, StyleSheet, StatusBar } from "react-native"; import Input from "../../src/components/input"; import { useState } from "react"; import { Picker } from "@react-native-picker/picker"; import * as SQLite from 'expo-sqlite'; const db = SQLite.openDatabase({ name: 'expenses.db', location: 'default', }); try { db.transaction((tx) => { tx.executeSql( 'CREATE TABLE IF NOT EXISTS expenses (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, amount REAL, category TEXT)', [], () => { console.log('Table created successfully.'); }, (error) => { console.log('Error creating table:', error); } ); }); } catch (error) { console.log('Error executing SQL statement:', error); } const AddExpense = () => { const [Category, setCategory] = useState("food"); const [Name, setName] = useState(""); const [Amount, setAmount] = useState(""); const Add = () => { console.log("Input 1:", Name); console.log("Input 2:", Amount); console.log("Input 3", Category); db.transaction(tx => { tx.executeSql( 'INSERT INTO expenses (Name, Amount, Category) VALUES (?, ?, ?)', [Name, Amount, Category], (_, { rowsAffected, insertId }) => { if (rowsAffected > 0) { console.log("Expense record inserted with ID:", {insertId}); } }, (_, error) => { console.log("Error inserting expense record:", error); } ); }); }; return ( <View style={styles.container}> <Text>GastoCalc</Text> <Input text={"Name Of Expense"} placeholder={"What did you spend on?"} multiline={false} value={Name} onChangeText={(text) => setName(text)} /> <Input text={"Expense Amount"} placeholder={"₹ ??"} inputMode={"numeric"} value={Amount} onChangeText={(text) => setAmount(text)} /> <View style={styles.inputContainer}> <Text style={styles.inputText}>Category Of Expense</Text> <View style={styles.inputBorder}> <Picker selectedValue={Category} onValueChange={(itemValue, itemIndex) => setCategory(itemValue)} style={styles.input} > <Picker.Item label="Food" value="food" /> <Picker.Item label="Rent" value="rent" /> <Picker.Item label="Fuel" value="fuel" /> <Picker.Item label="Miscellaneous" value="mics" /> </Picker> </View> </View> <View style={styles.buttonView}> <Pressable style={styles.addButton} onPress={Add}> <Text>ADD</Text> </Pressable> </View> </View> ); }; export default AddExpense; const styles = StyleSheet.create({ container: { flex: 1, marginTop: StatusBar.currentHeight, }, addButton: { backgroundColor: "lightgreen", alignItems: "center", justifyContent: "center", width: 75, height: 30, }, buttonView: { flex: 1, justifyContent: "flex-end", alignItems: "center", marginBottom: 30, }, input: { marginTop: -9, }, inputText: { fontSize: 15, alignItems: "baseline", }, inputContainer: { flexDirection: "column", alignItems: "center", marginLeft: 15, }, inputBorder: { borderWidth: 1, height: 40, width: 240, marginTop: 10, }, });
问题原因
- Expo SDK 48+版本中,
expo-sqlite的同步openDatabase方法已被废弃,改用异步的openDatabaseAsync,同步调用无法正确初始化数据库实例。 - 在组件外部同步执行数据库初始化,可能在React Native环境未完全就绪时触发,导致API调用失败,
db变量未被正确赋值。
解决方案
将数据库初始化改为异步方式,放在组件内部的useEffect中执行,并用状态存储数据库实例,确保操作时实例已就绪:
修改后的完整代码
import { View, Text, Pressable, StyleSheet, StatusBar } from "react-native"; import Input from "../../src/components/input"; import { useState, useEffect } from "react"; import { Picker } from "@react-native-picker/picker"; import * as SQLite from 'expo-sqlite'; const AddExpense = () => { const [Category, setCategory] = useState("food"); const [Name, setName] = useState(""); const [Amount, setAmount] = useState(""); const [db, setDb] = useState(null); // 异步初始化数据库 useEffect(() => { const initDb = async () => { try { // 使用异步方法打开数据库 const database = await SQLite.openDatabaseAsync('expenses.db'); setDb(database); // 创建表(使用execAsync简化操作) await database.execAsync(` CREATE TABLE IF NOT EXISTS expenses ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, amount REAL, category TEXT ); `); console.log('Table created successfully.'); } catch (error) { console.log('Error initializing database:', error); } }; initDb(); }, []); const Add = async () => { // 检查数据库是否已初始化 if (!db) { console.log('Database not initialized yet'); return; } console.log("Input 1:", Name); console.log("Input 2:", Amount); console.log("Input 3", Category); try { // 使用runAsync执行插入操作 const result = await db.runAsync( 'INSERT INTO expenses (name, amount, category) VALUES (?, ?, ?)', [Name, Amount, Category] ); if (result.changes > 0) { console.log("Expense record inserted with ID:", result.lastInsertRowId); } } catch (error) { console.log("Error inserting expense record:", error); } }; // 数据库未就绪时显示加载状态 if (!db) { return ( <View style={styles.container}> <Text>Loading...</Text> </View> ); } return ( <View style={styles.container}> <Text>GastoCalc</Text> <Input text={"Name Of Expense"} placeholder={"What did you spend on?"} multiline={false} value={Name} onChangeText={(text) => setName(text)} /> <Input text={"Expense Amount"} placeholder={"₹ ??"} inputMode={"numeric"} value={Amount} onChangeText={(text) => setAmount(text)} /> <View style={styles.inputContainer}> <Text style={styles.inputText}>Category Of Expense</Text> <View style={styles.inputBorder}> <Picker selectedValue={Category} onValueChange={(itemValue, itemIndex) => setCategory(itemValue)} style={styles.input} > <Picker.Item label="Food" value="food" /> <Picker.Item label="Rent" value="rent" /> <Picker.Item label="Fuel" value="fuel" /> <Picker.Item label="Miscellaneous" value="mics" /> </Picker> </View> </View> <View style={styles.buttonView}> <Pressable style={styles.addButton} onPress={Add}> <Text>ADD</Text> </Pressable> </View> </View> ); }; export default AddExpense; const styles = StyleSheet.create({ container: { flex: 1, marginTop: StatusBar.currentHeight, alignItems: 'center', justifyContent: 'center', }, addButton: { backgroundColor: "lightgreen", alignItems: "center", justifyContent: "center", width: 75, height: 30, }, buttonView: { flex: 1, justifyContent: "flex-end", alignItems: "center", marginBottom: 30, }, input: { marginTop: -9, }, inputText: { fontSize: 15, alignItems: "baseline", }, inputContainer: { flexDirection: "column", alignItems: "center", marginLeft: 15, }, inputBorder: { borderWidth: 1, height: 40, width: 240, marginTop: 10, }, });
关键修改点
- 用
SQLite.openDatabaseAsync替代同步的openDatabase,确保数据库实例正确初始化。 - 将数据库初始化逻辑放在组件的
useEffect中,确保在组件挂载后执行,避免环境未就绪的问题。 - 新增
db状态存储数据库实例,在操作前检查实例是否存在,避免调用未初始化的对象。 - 使用
execAsync和runAsync等异步API替代旧的transaction和executeSql,符合新版Expo SQLite的API规范。
内容的提问来源于stack exchange,提问作者jay shah
相关产品推荐
相关产品推荐

