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

使用Expo+SQLite数据库时事务的成功/错误回调均未触发

问题描述

我参考了Expo文档中关于SQLite的示例及其他相关示例,但代码始终无法正常运行。为调试问题,我添加了成功和错误回调,然而这两个回调均未被触发。以下是我的测试代码:

import React, { useState, useEffect } from 'react';
import { Platform, ScrollView, StyleSheet, Text, TextInput, TouchableOpacity, View, Button, } from "react-native";
import * as SQLite from "expo-sqlite";

function App(props) {
  function openDatabase() {
    if (Platform.OS === "web") {
      return {
        transaction: () => {
          return {
            executeSql: () => {},
          };
        },
      };
    }
    const db = SQLite.openDatabase("db.db");
    return db;
  };
  
  const db = openDatabase();
  const [text, setText] = useState(null);
  const [forceUpdate, forceUpdateId] = useForceUpdate();

  useEffect(() => {
    console.log("Use Effect"); // this gets logged
    db.transaction((tx) => {
      tx.executeSql(
        "create table if not exists items (id integer primary key not null, done int, value text);",
        [],
        (_, res) => {console.log("Error initializing database!");},
        (_, err) => {console.log("Database was initialized");}
      );
    },
    [],
    (_, res) => {console.log("Error initializing database!");},
    (_, err) => {console.log("Database was initialized");});
  }, []);

  return (
    <View style={styles.container}>
      <Text>Test</Text>
    </View>
  );
}

function useForceUpdate() {
  const [value, setValue] = useState(0);
  return [() => setValue(value + 1), value];
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center'
  }
});

export default App;
问题分析与修复

核心问题点

  • tx.executeSql回调顺序颠倒:executeSql的参数顺序为(SQL语句, 参数数组, 成功回调, 错误回调),你将成功提示与错误提示的回调写反,且顺序错误会导致逻辑完全混乱。
  • db.transaction参数格式错误:transaction的正确参数结构是(事务处理函数, 事务错误回调, 事务成功回调),你在事务处理函数后额外添加了[],导致后续的回调函数无法被正确绑定,这是回调完全不触发的关键原因。
  • Web端模拟未处理回调:Web环境下的模拟数据库对象没有调用传入的回调函数,所以不会输出日志,需要补充回调触发逻辑。
  • useForceUpdate存在闭包问题:状态更新时直接使用value + 1会导致闭包陷阱,且未将其加入useEffect依赖数组(若后续需用它触发更新)。

修复后的代码

import React, { useState, useEffect } from 'react';
import { Platform, StyleSheet, Text, View } from "react-native";
import * as SQLite from "expo-sqlite";

function App(props) {
  function openDatabase() {
    if (Platform.OS === "web") {
      return {
        transaction: (txCallback) => {
          // Web端模拟事务逻辑,确保触发回调
          const mockTx = {
            executeSql: (sql, params, successCb, errorCb) => {
              // 模拟SQL执行成功,调用成功回调
              successCb?.(null, { rows: { _array: [] } });
            }
          };
          txCallback(mockTx);
          return {};
        },
      };
    }
    const db = SQLite.openDatabase("db.db");
    return db;
  };
  
  const db = openDatabase();
  const [text, setText] = useState(null);
  const [forceUpdate, forceUpdateId] = useForceUpdate();

  useEffect(() => {
    console.log("Use Effect");
    db.transaction(
      (tx) => {
        tx.executeSql(
          "create table if not exists items (id integer primary key not null, done int, value text);",
          [],
          // SQL执行成功回调
          (_, res) => {console.log("Database was initialized");},
          // SQL执行错误回调
          (_, err) => {console.log("Error initializing database!", err);}
        );
      },
      // 事务整体错误回调
      (err) => {console.log("Transaction failed!", err);},
      // 事务整体成功回调
      () => {console.log("Transaction completed successfully");}
    );
  }, [forceUpdateId]); // 加入依赖,确保forceUpdate时重新执行

  return (
    <View style={styles.container}>
      <Text>Test</Text>
    </View>
  );
}

function useForceUpdate() {
  const [value, setValue] = useState(0);
  // 使用函数式更新避免闭包问题
  return [() => setValue(prev => prev + 1), value];
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center'
  }
});

export default App;

修复说明

  1. 调整tx.executeSql的回调顺序,将成功提示与错误提示对应到正确的回调逻辑中。
  2. 移除db.transaction参数中多余的[],让事务的错误和成功回调正常绑定并触发。
  3. 完善Web端模拟数据库的executeSql方法,确保回调函数被触发,方便Web环境调试。
  4. 修复useForceUpdate的状态更新逻辑,使用函数式更新避免闭包问题,并将forceUpdateId加入useEffect依赖数组(若后续需通过它触发组件更新)。

内容的提问来源于stack exchange,提问作者Appa

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 19:10:29