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;
三、额外优化说明
- 内存占用说明:10万行仅包含
Word和Id的数据体积极小(按平均每个单词10字符计算,总数据量约2-3MB),完全不会造成内存压力。 - 备选方案:如果确实不想一次性加载全部数据,可以给SQLite表创建FTS5全文索引,优化数据库搜索速度,但内存搜索仍会是响应最快的方案。
内容的提问来源于stack exchange,提问作者kiflay
相关产品推荐
相关产品推荐

