You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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,
  },
});

问题原因

  1. Expo SDK 48+版本中,expo-sqlite的同步openDatabase方法已被废弃,改用异步的openDatabaseAsync,同步调用无法正确初始化数据库实例。
  2. 在组件外部同步执行数据库初始化,可能在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 20:35:53