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

React Native使用AsyncStorage实现待办任务本地存储失效问题求助

问题排查与修复方案

现有代码的核心问题

  • 缺少AsyncStorage的依赖安装与导入:React Native 0.60+版本已将AsyncStorage从核心库移除,需单独安装并导入才可使用
  • AsyncStorage仅支持存储字符串类型数据:直接存储任务文本、数组格式的任务列表都会存储失败,必须先通过JSON.stringify()序列化为字符串,读取时通过JSON.parse()反序列化为原格式
  • 存储逻辑触发时机错误:添加任务时没有调用存储方法,删除任务时反而存储了已清空的单个task变量,没有存储更新后的完整任务列表
  • 缺少初始化读取逻辑:应用启动时没有从本地存储读取之前保存的任务数据,导致重启后数据无法恢复
  • 未存储任务的指派人员信息:当前任务仅存了文本内容,下拉选择的指派人员没有关联保存到任务数据中,重启后指派信息会丢失

前置操作

先安装AsyncStorage依赖:

npm install @react-native-async-storage/async-storage
# 或使用yarn
yarn add @react-native-async-storage/async-storage

如果是iOS环境还需要执行cd ios && pod install完成原生依赖关联。

修正后的完整代码

import React, {useState, useEffect} from 'react';
import { KeyboardAvoidingView, Text, View, TextInput, TouchableOpacity, Keyboard, ScrollView } from 'react-native';
import AsyncStorage from '@react-native-async-storage/async-storage';
import Task from '../../Task';
import SelectDropdown from 'react-native-select-dropdown'
import styles from "../../../assets/styles"

export default function Trucs() {
  const [task, setTask] = useState('');
  const [taskItems, setTaskItems] = useState([]);
  const users = ["Jibé", "Charly"]
  // 存储key统一抽离,避免写错
  const STORAGE_KEY = 'TODO_TASKS'

  // 组件挂载时读取本地存储的任务数据初始化
  useEffect(() => {
    const loadTasks = async () => {
      try {
        const savedTasks = await AsyncStorage.getItem(STORAGE_KEY)
        if(savedTasks !== null) {
          setTaskItems(JSON.parse(savedTasks))
        }
      } catch (e) {
        console.log('加载任务失败:', e)
      }
    }
    loadTasks()
  }, [])

  // 监听任务列表变化,自动同步到本地存储
  useEffect(() => {
    const saveTasks = async () => {
      try {
        await AsyncStorage.setItem(STORAGE_KEY, JSON.stringify(taskItems))
      } catch (e) {
        console.log('保存任务失败:', e)
      }
    }
    saveTasks()
  }, [taskItems])

  const handleAddTask = () => {
    Keyboard.dismiss();
    if(!task.trim()) return // 空任务不添加
    // 任务改为对象格式,同时存储文本和默认指派人员
    setTaskItems([...taskItems, {text: task, assignedUser: null}])
    setTask('');
  }

  const completeTask = (index) => {
    let itemsCopy = [...taskItems];
    itemsCopy.splice(index, 1);
    setTaskItems(itemsCopy)
  }

  // 更新任务的指派人员
  const updateAssignedUser = (taskIndex, user) => {
    const itemsCopy = [...taskItems]
    itemsCopy[taskIndex].assignedUser = user
    setTaskItems(itemsCopy)
  }

  return (
    <View style={styles.wrap}>
      <ScrollView
        contentContainerStyle={{
          flexGrow: 1
        }}
        keyboardShouldPersistTaps='handled'
      >
        <View style={styles.tasksWrapper}>
          <Text style={styles.sectionTitle}>Trucs à faire</Text>
            {
              taskItems.map((item, index) => {
                return (
                  <TouchableOpacity key={index}  onPress={()  => completeTask(index)}>
                      <View>
                          <Task text={item.text}/>
                          <SelectDropdown
                            data={users}
                            defaultValue={item.assignedUser}
                            onSelect={(selectedItem) => {
                              updateAssignedUser(index, selectedItem)
                            }}
                            buttonTextAfterSelection={(selectedItem) => {
                              return selectedItem
                            }}
                            rowTextForSelection={(item) => {
                              return item
                            }}/>
                      </View>
                  </TouchableOpacity>
                )
              })
            }
        </View>
      </ScrollView>
      <KeyboardAvoidingView
        style={styles.writeTaskWrapper}
      >
        <TextInput style={styles.input} placeholder={'Rajouter un truc à faire'} value={task} onChangeText={text => setTask(text)} />
        <TouchableOpacity onPress={() => handleAddTask()}>
          <View style={styles.addWrapper}>
            <Text style={styles.addText}>+</Text>
          </View>
        </TouchableOpacity>
      </KeyboardAvoidingView>
    </View>
  );
}

核心函数逻辑说明

  1. AsyncStorage.setItem(key, value):异步持久化存储方法,只能接收字符串类型的键和值,会将数据存到设备本地,应用卸载前都不会丢失。我们这里通过JSON.stringify(taskItems)将数组类型的任务列表转为字符串后存储。
  2. AsyncStorage.getItem(key):异步读取方法,根据传入的键读取对应的存储值,返回的是字符串类型,我们通过JSON.parse()将字符串转回数组格式的任务列表,赋值给state完成初始化。
  3. 两个useEffect的作用:
    • 第一个仅在组件挂载时执行一次,负责读取本地存储的历史任务初始化列表
    • 第二个监听taskItems的变化,只要任务列表有新增、删除、修改指派人员的操作,就自动同步最新的列表到本地存储,不需要手动在每个修改操作里调用存储方法,避免遗漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 05:18:05