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

React Native预填充SQLite数据库加载缓慢及搜索异常问题咨询

解决方案:React Native中缓存静态SQLite数据优化搜索体验

一、先修复当前代码的异步问题

你当前日志显示空数组的核心原因是executeSqlQuery是异步操作,但你用了同步返回的写法——db.transaction和tx.executeSql都是异步执行的,还没等数据查询完成就返回了空数组,导致后续拿不到数据。

修正后的异步查询函数

const db = SQLite.openDatabase({
  name: 'DictionaryG.db',
  createFromLocation: '~DictionaryG.db',
  location: 'Library',
});

// 用Promise封装异步查询,确保能拿到正确结果
export const executeSqlQuery = (query) => {
  return new Promise((resolve, reject) => {
    db.transaction((tx) => {
      tx.executeSql(
        query,
        [],
        (tx, results) => {
          const words = [];
          for (let i = 0; i < results.rows.length; ++i) {
            words.push(results.rows.item(i));
          }
          resolve(words);
        },
        (error) => reject(error)
      );
    });
  });
};

二、实现全局内存缓存,避免重复加载数据库

因为你的10万行数据是静态不变的,最直接的优化是一次性加载所有数据到内存缓存,后续搜索直接在内存中过滤,彻底消除数据库访问的延迟。

1. 全局缓存工具函数

创建一个全局缓存模块,确保数据只加载一次:

import { executeSqlQuery } from './your-db-file-path';

// 全局缓存变量,存储所有词汇
let cachedWords = [];
// 标记是否正在加载数据,避免重复发起请求
let isLoading = false;

export const getCachedWords = async () => {
  // 如果已有缓存,直接返回
  if (cachedWords.length > 0) {
    return cachedWords;
  }
  // 如果正在加载,等待后重试,防止重复请求
  if (isLoading) {
    await new Promise(resolve => setTimeout(resolve, 100));
    return getCachedWords();
  }

  isLoading = true;
  try {
    // 一次性加载所有静态数据
    const allWords = await executeSqlQuery('SELECT Word,Id FROM EnglishWords');
    cachedWords = allWords;
    return allWords;
  } catch (error) {
    console.error('加载词汇数据失败:', error);
    return [];
  } finally {
    isLoading = false;
  }
};

2. 组件中使用缓存并实现实时搜索

import React, { useState, useEffect, useCallback } from 'react';
import { View, Text, TextInput, ActivityIndicator } from 'react-native';
import { getCachedWords } from './your-cache-file-path';

const MainHome = () => {
  const [allWords, setAllWords] = useState([]);
  const [searchQuery, setSearchQuery] = useState('');
  const [filteredWords, setFilteredWords] = useState([]);
  const [isDataLoading, setIsDataLoading] = useState(true);

  // 加载缓存数据
  const loadData = useCallback(async () => {
    setIsDataLoading(true);
    const words = await getCachedWords();
    setAllWords(words);
    // 初始显示前5条数据
    setFilteredWords(words.slice(0, 5));
    setIsDataLoading(false);
  }, []);

  useEffect(() => {
    loadData();
  }, [loadData]);

  // 实时搜索:直接在内存中过滤数据,无延迟
  useEffect(() => {
    if (!searchQuery) {
      setFilteredWords(allWords.slice(0, 5));
      return;
    }
    const lowerQuery = searchQuery.toLowerCase();
    const filtered = allWords.filter(word => 
      word.Word.toLowerCase().includes(lowerQuery)
    );
    setFilteredWords(filtered);
  }, [searchQuery, allWords]);

  // 加载状态显示
  if (isDataLoading) {
    return (
      <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
        <ActivityIndicator size="large" />
      </View>
    );
  }

  return (
    <View style={{ flex: 1, padding: 16 }}>
      <Text>主首页</Text>
      {/* 搜索输入框 */}
      <TextInput
        style={{ 
          height: 40, 
          borderColor: 'gray', 
          borderWidth: 1, 
          marginVertical: 16, 
          paddingHorizontal: 8 
        }}
        placeholder="搜索词汇"
        value={searchQuery}
        onChangeText={setSearchQuery}
      />
      {/* 显示搜索结果 */}
      {filteredWords.map(item => (
        <View key={item.Id} style={{ marginVertical: 8 }}>
          <Text>{item.Word}</Text>
        </View>
      ))}
    </View>
  );
};

export default MainHome;

三、额外优化说明

  1. 内存占用说明:10万行仅包含Word和Id的数据体积极小(按平均每个单词10字符计算,总数据量约2-3MB),完全不会造成内存压力。
  2. 备选方案:如果确实不想一次性加载全部数据,可以给SQLite表创建FTS5全文索引,优化数据库搜索速度,但内存搜索仍会是响应最快的方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 05:10:07