React Native中expo-sqlite存储任务重启后消失的问题求助
React Native任务数据持久化问题排查与修复
我正在开发一款管理笔记和任务的React Native应用,分别为两者创建了对应的数据表。笔记的保存和展示功能完全正常,但任务功能存在问题:任务创建后能在组件中正常显示,但重新加载或关闭应用后就会消失。任务相关组件逻辑和笔记组件基本一致,仅针对任务做了少量扩展。以下是任务创建、展示及容器组件的代码,求帮助排查问题。
创建任务组件
import React, { useState } from 'react'; import { ScrollView, StyleSheet, Text, View, TextInput, Pressable } from 'react-native'; import Icon from "react-native-vector-icons/Ionicons"; import { useDataContext } from '../dataProviders/DataProvider'; import { db } from '../database/database'; export default function CreateTasks() { const { handleAddTask } = useDataContext(); const [taskTitle, setTaskTitle] = useState(''); const [taskDate, setTaskDate] = useState(''); const [taskTime, setTaskTime] = useState(''); const [taskDescription, setTaskDescription] = useState(''); const addTask = () => { const newValue = { taskTitle: taskTitle, date: taskDate, time: taskTime, taskDescription: taskDescription, }; setTaskTitle(newValue.taskTitle); setTaskDate(newValue.date); setTaskTime(newValue.time); setTaskDescription(newValue.taskDescription); db.transaction( (tx) => { tx.executeSql( 'insert into tasks ( title, date, time, description) values(?, ?, ?, ?)', [newValue.taskTitle, newValue.date, newValue.time, newValue.taskDescription] ); }, ); handleAddTask(newValue); setTaskTitle(''); // Clear the input fields setTaskDate(''); setTaskTime(''); setTaskDescription(''); }; return ( <View style={styles.container}> <ScrollView style={styles.inputArea}> <TextInput style={styles.inputTitle} value={taskTitle} onChangeText={taskTitle => setTaskTitle(taskTitle)} placeholder='Task' /> <TextInput style={styles.inputDate} value={taskDate} onChangeText={date => setTaskDate(date)} keyboardType='default' placeholder='xx/xx/xxxx' /> <TextInput style={styles.inputTime} value={taskTime} onChangeText={time => setTaskTime(time)} keyboardType='default' placeholder='00:00' /> <TextInput style={styles.input} value={taskDescription} onChangeText={taskDescription => setTaskDescription(taskDescription)} multiline={true} keyboardType='default' placeholder='Description...' /> </ScrollView> <View style={styles.buttonContainer}> <Pressable onPress={() => addTask()}> <Icon name={"bookmark"} //color="#87CEFA" size={40} /> </Pressable> </View> </View> ) }
展示任务组件
import React, { useState, useEffect } from 'react'; import { ScrollView, StyleSheet, Text, View, TextInput, Pressable, Alert } from 'react-native'; import TaskContainer from './TaskContainer'; import EditTasks from './EditTasks'; import { useDataContext } from '../dataProviders/DataProvider'; import { getTasks, insertIntoDeletedTasks, removeTask } from '../database/database'; import { Provider } from 'react-native-paper'; import Icon from "react-native-vector-icons/Ionicons"; export default function Tasks() { const { taskItems, setTaskItems } = useDataContext(); useEffect(() => { (async () => { try { const fetchedTasks = await getTasks(); setTaskItems(fetchedTasks); } catch (error) { console.error('Error fetching notes:', error); Alert.alert('Error fetching tasks. Please try again.'); } })(); }, []); const [searchQuery, setSearchQuery] = useState(''); const regex = new RegExp(searchQuery, 'i'); const filteredData = taskItems.filter(item => regex.test(item.taskTitle) ); const moveTaskToDeletedTasks = async (taskData) => { try { insertIntoDeletedTasks(taskData) } catch (error) { console.error('Error moving note to deletedNotes:', error); throw new Error('Error moving note to deletedNotes.'); } }; const deleteTask = (index) => { // Show a confirmation dialog Alert.alert( 'Delete Task', 'Are you sure you want to delete this task?', [ { text: 'Cancel', style: 'cancel', }, { text: 'Delete', style: 'destructive', onPress: () => { // If the user confirms, delete the task let deletedTask = taskItems[index]; // Move the note to deletedNotes table moveTaskToDeletedTasks(deletedTask); // Remove the note from noteItems let itemsCopyTask = [...taskItems]; itemsCopyTask.splice(index, 1); setTaskItems(itemsCopyTask); // Perform the actual deletion of the note from the Notes table removeTask(deletedTask); }, }, ], { cancelable: true } ); } return ( <Provider> <View style={styles.mainContainer}> <View style={styles.searchBox}> <TextInput placeholder="Search..." onChangeText={(text) => setSearchQuery(text)} value={searchQuery} style={styles.input} /> <Icon name="search-outline" size={40} /> </View> <ScrollView> <View style={styles.container}> {filteredData.map((item, index) => ( item && item.taskTitle ? ( // Check if 'item' exists and has a 'title' property <Pressable key={index} onPress={() => deleteTask(index)} > <TaskContainer taskTitle={item.taskTitle} date={item.date} time={item.time} taskDescription={item.taskDescription} index={index} task={item} /> </Pressable> ) : null ))} </View> </ScrollView> <EditTasks /> </View> </Provider> ) }
任务容器组件
import React from 'react'; import { StyleSheet, Text, View, Pressable } from 'react-native'; import Icon from "react-native-vector-icons/Ionicons"; import { useDataContext } from '../dataProviders/DataProvider'; export default function TaskContainer(props) { const { showDialogTask } = useDataContext(); const { task } = props; return ( <View styles={styles.container}> <View style={styles.TaskContainer}> <View style={styles.box1}> <View style={styles.box11}> <Text style={styles.titleItem}>Task</Text> <Text style={styles.text} ellipsizeMode="tail" numberOfLines={1}>{task.taskTitle}</Text> </View> </View> <View style={styles.box2}> <View style={styles.box22}> <Text style={styles.titleItem}>Date</Text> <Text style={styles.text}>{task.date}</Text> </View> <View style={styles.box22}> <Text style={styles.titleItem}>Time</Text> <Text style={styles.text}>{task.time}</Text> </View> </View> <View style={styles.box3}> <View> <Text style={styles.text} ellipsizeMode="tail" numberOfLines={1}>{task.taskDescription}</Text> </View> </View> <View style={styles.box4}> <Pressable onPress={() => showDialogTask(task)}> <Icon name="create-outline" size={40} /> </Pressable> </View> </View> </View> ); }
问题排查与修复方案
1. 数据库插入逻辑异步处理缺失
CreateTasks组件的addTask函数中,SQLite事务是异步操作,但当前代码未等待事务完成就更新上下文状态并清空输入,可能导致数据未写入数据库就刷新状态,或事务失败无错误提示。
修复:
给事务添加成功/失败回调,确保数据写入后再更新状态:
const addTask = () => { const newValue = { taskTitle: taskTitle, date: taskDate, time: taskTime, taskDescription: taskDescription, }; db.transaction( (tx) => { tx.executeSql( 'insert into tasks ( title, date, time, description) values(?, ?, ?, ?)', [newValue.taskTitle, newValue.date, newValue.time, newValue.taskDescription], (_, result) => { // 插入成功后更新上下文,带上数据库自增ID handleAddTask({...newValue, id: result.insertId}); // 清空输入 setTaskTitle(''); setTaskDate(''); setTaskTime(''); setTaskDescription(''); } ); }, (error) => { console.error('任务插入失败:', error); alert('保存任务失败,请重试'); } ); };
2. 数据库字段与组件字段映射不匹配
数据库表中字段是title和description,但组件中使用的是taskTitle和taskDescription,getTasks查询返回的数据结构未做映射,导致读取后字段不匹配,无法正确渲染或存储。
修复:
在database.js的getTasks函数中映射字段:
export const getTasks = async () => { return new Promise((resolve, reject) => { db.transaction((tx) => { tx.executeSql('select * from tasks', [], (_, { rows }) => { const tasks = rows._array.map(item => ({ id: item.id, taskTitle: item.title, date: item.date, time: item.time, taskDescription: item.description })); resolve(tasks); }, (_, error) => { reject(error); }); }); }); };
3. 任务容器组件样式语法错误
TaskContainer最外层View使用了styles={styles.container},正确语法应为style={styles.container}(多了一个s),虽不影响数据持久化,但建议修复以保证样式生效。
4. 上下文状态初始化验证
检查DataProvider中taskItems初始值是否为数组,handleAddTask是否正确将新任务添加到数组中,确保状态更新逻辑和笔记组件一致。
内容的提问来源于stack exchange,提问作者Alexandre Leal
相关产品推荐
相关产品推荐

