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

React Native:AsyncStorage仅一个计数器持久化生效问题求助

问题排查与修复

你的代码核心问题是初始挂载时,保存数据的逻辑会覆盖刚从AsyncStorage读取的值:

组件挂载流程:

  1. 执行get()函数读取本地存储的旧值,调用setCounter和setCounter2更新状态(但React状态更新是异步的,此时counter和counter2仍为初始值0)。
  2. 依赖[counter, counter2]的useEffect触发,调用saving()将初始值0写入本地存储,直接覆盖了刚读取的旧值。

这就是为什么counter2无法持久化——每次启动应用都会被重置为0,而counter看起来正常是因为你点击按钮后会触发新的保存操作,覆盖掉初始的0值。

修复后的代码

import React, { useEffect, useState } from "react";
import { View, Text, StyleSheet, Button } from "react-native";
import AsyncStorage from "@react-native-async-storage/async-storage";

const Home = () => {
  const [counter, setCounter] = useState(0);
  const [counter2, setCounter2] = useState(0);
  // 添加加载状态,标记是否完成初始数据读取
  const [loaded, setLoaded] = useState(false);

  // 读取本地存储数据
  const get = async () => {
    const values = await AsyncStorage.multiGet(["@count", "@count2"]);
    values.forEach(([key, value]) => {
      if (key === "@count") {
        const savedCount = parseInt(value) || 0;
        setCounter(savedCount);
      }
      if (key === "@count2") {
        const savedCount2 = parseInt(value) || 0;
        setCounter2(savedCount2);
      }
    });
    // 读取完成后标记加载状态为true
    setLoaded(true);
  };

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

  const increment = () => {
    setCounter(pre => pre + 1);
  };

  const increment2 = () => {
    setCounter2(pre => pre + 1);
  };

  // 优化:用multiSet替代两次setItem,提升效率
  const saving = async () => {
    await AsyncStorage.multiSet([
      ["@count", counter.toString()],
      ["@count2", counter2.toString()]
    ]);
  };

  // 仅当加载完成后,才在状态变化时保存数据
  useEffect(() => {
    if (loaded) {
      saving();
    }
  }, [counter, counter2, loaded]);

  const clearAll = async () => {
    try {
      await AsyncStorage.clear();
      // 清空后重置状态,保证界面与数据一致
      setCounter(0);
      setCounter2(0);
    } catch (e) {
      console.error("清空存储失败:", e);
    }
    console.log("Done.");
  };

  return (
    <View style={styles.container}>
      <Text style={styles.text}>{counter}</Text>
      <Text style={styles.text}>{counter2}</Text>

      <Button title="count up" onPress={increment} />
      <Button title="count up2" onPress={increment2} />
      <Button title="All clear" onPress={clearAll} />
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    justifyContent: "center",
    alignItems: "center",
    flex: 1,
  },
  text: {
    fontSize: 50,
  },
});

export default Home;

关键修改点

  1. 添加loaded状态:标记初始数据读取是否完成,避免初始挂载时的保存操作覆盖旧值。
  2. 优化存储操作:使用multiSet替代两次setItem,减少异步IO次数。
  3. 清空功能增强:清空存储后同步重置状态,保证界面显示与本地数据一致。
  4. 移除不必要的async:increment和increment2函数不需要async修饰,因为setState是同步调用(状态更新本身是异步的,但函数执行是同步的)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 07:42:51