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

React Native中如何用Async Storage构建可新增的Workout数组?

解决React Native Async Storage Workout数组问题

核心问题分析

你当前的代码存在三个关键问题:

  • 把训练的每个字段(名称、组数等)单独存在AsyncStorage中,每次提交会直接覆盖旧值,无法保存多条训练记录
  • AsyncStorage的getItem是异步操作,你没有加await,导致拿到的是Promise对象而非实际数据
  • 状态管理错误,应该维护一个训练数组而非单个字段的状态

解决方案代码

以下是修改后的完整代码,实现类似TodoList的新增训练、实时刷新功能:

1. WorkoutTile 页面(训练提交页)

import { View, TextInput, Button, Alert } from 'react-native';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { useState } from 'react';

const WorkoutTile = ({ navigation }) => {
  const [name, setName] = useState('');
  const [sets, setSets] = useState('');
  const [reps, setReps] = useState('');
  const [weight, setWeight] = useState('');

  const onSubmit = async () => {
    try {
      // 验证必填字段
      if (!name || !sets || !reps || !weight) {
        Alert.alert('提示', '请填写所有训练信息');
        return;
      }

      // 读取已存储的训练数组
      const storedWorkouts = await AsyncStorage.getItem('workouts');
      const workouts = storedWorkouts ? JSON.parse(storedWorkouts) : [];

      // 组装新训练项(添加唯一ID方便后续操作)
      const newWorkout = {
        id: Date.now().toString(),
        name,
        sets: parseInt(sets),
        reps: parseInt(reps),
        weight: parseFloat(weight),
      };

      // 更新数组并存回AsyncStorage
      workouts.push(newWorkout);
      await AsyncStorage.setItem('workouts', JSON.stringify(workouts));

      // 返回主页面
      navigation.navigate('Body');
    } catch (error) {
      Alert.alert('错误', error.message);
    }
  };

  return (
    <View style={{ padding: 20, marginTop: 20 }}>
      <TextInput
        placeholder="训练名称"
        value={name}
        onChangeText={setName}
        style={{ borderBottomWidth: 1, marginBottom: 12, paddingVertical: 8 }}
      />
      <TextInput
        placeholder="组数"
        value={sets}
        onChangeText={setSets}
        keyboardType="numeric"
        style={{ borderBottomWidth: 1, marginBottom: 12, paddingVertical: 8 }}
      />
      <TextInput
        placeholder="次数"
        value={reps}
        onChangeText={setReps}
        keyboardType="numeric"
        style={{ borderBottomWidth: 1, marginBottom: 12, paddingVertical: 8 }}
      />
      <TextInput
        placeholder="重量"
        value={weight}
        onChangeText={setWeight}
        keyboardType="numeric"
        style={{ borderBottomWidth: 1, marginBottom: 20, paddingVertical: 8 }}
      />
      <Button title="提交训练" onPress={onSubmit} />
    </View>
  );
};

export default WorkoutTile;

2. Body 页面(主展示页)

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

const Body = ({ navigation }) => {
  const [workouts, setWorkouts] = useState([]);

  // 组件加载和页面聚焦时刷新训练数据
  useEffect(() => {
    loadWorkouts();
    const unsubscribe = navigation.addListener('focus', loadWorkouts);
    return unsubscribe;
  }, [navigation]);

  const loadWorkouts = async () => {
    try {
      const storedWorkouts = await AsyncStorage.getItem('workouts');
      if (storedWorkouts) {
        setWorkouts(JSON.parse(storedWorkouts));
      }
    } catch (error) {
      Alert.alert('错误', error.message);
    }
  };

  // 渲染单个训练卡片
  const renderWorkoutItem = ({ item }) => (
    <View style={styles.tile}>
      <Text style={styles.tileTitle}>{item.name}</Text>
      <Text>组数: {item.sets}</Text>
      <Text>次数: {item.reps}</Text>
      <Text>重量: {item.weight}kg</Text>
    </View>
  );

  return (
    <View style={styles.container}>
      <Button title="添加新训练" onPress={() => navigation.navigate('WorkoutTile')} />
      <FlatList
        data={workouts}
        keyExtractor={(item) => item.id}
        renderItem={renderWorkoutItem}
        style={{ marginTop: 20 }}
      />
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 20,
    marginTop: 20,
  },
  tile: {
    backgroundColor: '#f5f5f5',
    padding: 16,
    borderRadius: 8,
    marginBottom: 10,
  },
  tileTitle: {
    fontSize: 18,
    fontWeight: '600',
    marginBottom: 6,
  },
});

export default Body;

关键改进点说明

  • 统一存储数组:用workouts作为唯一key存储整个训练数组,避免单字段覆盖问题
  • 异步操作规范:所有AsyncStorage操作都加await,确保拿到实际数据而非Promise
  • 实时刷新:监听页面焦点事件,从提交页返回时自动加载最新数据,无需重启App
  • 数据类型处理:将组数、次数转为整数,重量转为浮点数,避免字符串类型导致的渲染错误
  • 唯一ID:给每个训练项添加基于时间戳的ID,保证FlatList渲染的唯一性

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 04:47:02