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

React Native训练会话中可更新数据存储方案选型咨询

React Native训练会话数据管理方案选择

针对你需要在训练会话期间跨组件共享并持久化多组训练数据的场景,下面是具体的方案分析和实现建议:

首选方案:useReducer + useContext

不需要额外引入第三方库,用React原生API就能搞定中等复杂度的状态管理,完全匹配你的需求:

1. 定义状态结构与Reducer

先明确训练数据的结构,再用Reducer统一处理状态更新逻辑:

// 初始状态:包含所有训练项、当前编辑的训练项、当前组索引
const initialState = {
  workouts: [], // 每个训练项格式:{ id: 123, name: "深蹲", sets: [{ weight: "80", reps: "10" }, ...] }
  currentWorkout: null,
  currentSetIndex: 0
};

function workoutReducer(state, action) {
  switch (action.type) {
    // 添加新训练项
    case 'ADD_WORKOUT':
      const newWorkout = { ...action.payload, id: Date.now(), sets: [] };
      return {
        ...state,
        workouts: [...state.workouts, newWorkout],
        currentWorkout: newWorkout
      };
    // 给当前训练项添加一组数据
    case 'ADD_SET':
      if (!state.currentWorkout) return state;
      const updatedWorkouts = state.workouts.map(item => 
        item.id === state.currentWorkout.id 
          ? { ...item, sets: [...item.sets, action.payload] }
          : item
      );
      return {
        ...state,
        workouts: updatedWorkouts,
        currentWorkout: { ...state.currentWorkout, sets: [...state.currentWorkout.sets, action.payload] }
      };
    // 更新某一组的重量/次数
    case 'UPDATE_SET':
      if (!state.currentWorkout) return state;
      const updatedSets = state.currentWorkout.sets.map((set, idx) => 
        idx === action.payload.index ? { ...set, ...action.payload.data } : set
      );
      const updatedWorkoutsForSet = state.workouts.map(item => 
        item.id === state.currentWorkout.id ? { ...item, sets: updatedSets } : item
      );
      return {
        ...state,
        workouts: updatedWorkoutsForSet,
        currentWorkout: { ...state.currentWorkout, sets: updatedSets }
      };
    default:
      return state;
  }
}

2. 创建Context全局共享状态

结合本地存储(AsyncStorage)实现数据持久化,确保App重启后数据不丢失:

import { createContext, useContext, useReducer, useEffect } from 'react';
import AsyncStorage from '@react-native-async-storage/async-storage';

const WorkoutContext = createContext();

export function WorkoutProvider({ children }) {
  const [state, dispatch] = useReducer(workoutReducer, initialState);

  // 初始化:从本地加载历史训练数据
  useEffect(() => {
    const loadSavedData = async () => {
      const saved = await AsyncStorage.getItem('training_sessions');
      if (saved) {
        dispatch({ type: 'LOAD_WORKOUTS', payload: JSON.parse(saved) });
      }
    };
    loadSavedData();
  }, []);

  // 状态更新时自动保存到本地
  useEffect(() => {
    const saveData = async () => {
      await AsyncStorage.setItem('training_sessions', JSON.stringify(state.workouts));
    };
    saveData();
  }, [state.workouts]);

  return (
    <WorkoutContext.Provider value={{ state, dispatch }}>
      {children}
    </WorkoutContext.Provider>
  );
}

// 自定义Hook,简化组件调用
export function useWorkout() {
  return useContext(WorkoutContext);
}

3. 在输入组件中使用

直接通过自定义Hook获取状态和更新方法,无需手动传值:

import { useState } from 'react';
import { useWorkout } from './WorkoutContext';

function SetInput() {
  const { dispatch, state } = useWorkout();
  const [weight, setWeight] = useState('');
  const [reps, setReps] = useState('');

  const handleAddSet = () => {
    if (!weight || !reps) return;
    dispatch({
      type: 'ADD_SET',
      payload: { weight, reps }
    });
    // 清空输入框
    setWeight('');
    setReps('');
  };

  return (
    <>
      <TextInput
        style={addItemStyles.input}
        value={weight}
        onChangeText={setWeight}
        keyboardType="number-pad"
        returnKeyType="done"
      />
      <TextInput
        label="Reps"
        style={addItemStyles.input}
        value={reps}
        onChangeText={setReps}
        keyboardType="number-pad"
        returnKeyType="done"
      />
      <Button title="添加当前组" onPress={handleAddSet} />
    </>
  );
}

备选方案:Redux

如果你的App后续会扩展复杂功能(比如多用户同步、训练数据统计、跨端同步等),可以考虑用Redux Toolkit来管理状态。但对于当前仅训练会话数据管理的场景,Redux会增加不必要的配置成本,属于过度设计。

不推荐方案:单纯useState

如果只是单个组件内管理少量状态,useState足够,但你需要跨组件共享多组训练数据,用useState会导致状态分散,后续维护和扩展会非常麻烦。

额外优化建议

  • 用MMKV替代AsyncStorage:MMKV是React Native生态中性能更高的本地存储方案,读写速度远快于AsyncStorage
  • 给每个训练项/组生成唯一ID:可以用Date.now()或者uuid库,方便后续的更新、删除操作
  • 添加数据校验:在提交组数据时,检查重量和次数是否为有效数字,避免无效数据存入

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 03:06:23