【问题标题】:How to handle asynchronous promises in a reducer如何在 reducer 中处理异步 promise
【发布时间】:2025-12-11 10:30:01
【问题描述】:

我是 redux 的新手,因此试图找出身份验证用例的简单示例。此代码的 Web 版本从 localstorage 获取初始状态,并设置为 localstorage。将此示例转换为 react-native 意味着 localstorage 更改为异步的 AsyncStorage 并返回一个 Promise。

如何在 reducer 中处理异步初始化器?

import { AsyncStorage } from 'react-native';
import {
  LOGIN_REQUEST, LOGIN_SUCCESS, LOGIN_FAILURE, LOGOUT_SUCCESS,
} from '../actions/login';


const initialState = {
  isFetching: false,
  token: null, // AsyncStorage.getItem('token'),
  profile: null, // AsyncStorage.getItem('profile'),
  isLoggedIn: false,
  errorMessage: null,
};

// The auth reducer. The starting state sets authentication
// based on a token in asyncstorage. In addition we would also null
// the token if we check that it's expired
export default (state = initialState, action) => {
  switch (action.type) {
    case LOGIN_REQUEST:
      return Object.assign({}, state, {
        isFetching: true,
        isLoggedIn: false,
        token: null,
        user: null,
        errorMessage: '',
      });
    case LOGIN_SUCCESS:
      // todo set the async
      // AsyncStorage.multiSet(['token', 'profile'], [action.token, action.profile])
      return Object.assign({}, state, {
        isFetching: false,
        isLoggedIn: true,
        token: action.token,
        user: action.profile,
        errorMessage: '',
      });
    case LOGIN_FAILURE:
      return Object.assign({}, state, {
        isFetching: false,
        isLoggedIn: false,
        token: null,
        errorMessage: action.message,
      });
    case LOGOUT_SUCCESS:
      // AsyncStorage.multiRemove(['token', 'profile'])
      return Object.assign({}, state, {
        isFetching: true,
        isLoggedIn: false,
        token: null,
      });
    default:
      return state;
  }
};

【问题讨论】:

    标签: javascript react-native redux react-redux


    【解决方案1】:

    创建一个动作创建者,用于从 AsyncStorage 获取初始数据。当您的应用程序加载时,使用 tokenprofile 的键分派操作(您可以在根组件的 componentDidMount 中执行此操作)。

    // create similar actions creators for 'setItem' and 'multiSet' ops
    export function loadLocalData(key) {
      return {
        types: [LOAD_LOCAL_DATA, LOAD_LOCAL_DATA_SUCCESS, LOAD_LOCAL_DATA_FAIL]
        asyncStoragePromise: () => AsyncStorage.getItem(key),
        key,
      }
    }
    

    现在为 AsyncStorage 操作创建一个 middleware。在创建 store 时确保您 applyMiddleware

    中间件最常见的用例是支持异步 没有太多样板代码或依赖库的操作 像处方药。它通过让您另外分派异步操作来实现 正常动作。

    export default function asyncStorageMiddleware() {
      return ({ dispatch, getState }) => next => (action) => {
        if (typeof action === 'function') {
          return action(dispatch, getState);
        }
    
        const { asyncStoragePromise, types, ...rest } = action;
    
        if (!asyncStoragePromise) {
          return next(action);
        }
    
        const [REQUEST, SUCCESS, FAILURE] = types;
    
        next({ ...rest, type: REQUEST });
    
        const actionPromise = asyncStoragePromise();
        actionPromise
          .then(result => next({ ...rest, result, type: SUCCESS }))
          .catch(error => next({ ...rest, error, type: FAILURE }));
    
        return actionPromise;
      };
    }
    

    最后是你的initialState

    const initialState = {
      isFetching: false,
      token: null,
      profile: null,
      isLoggedIn: false,
      errorMessage: null,
      localLoadErr: '',
    };
    

    减速器

    LOAD_LOCAL_DATA_SUCCESS:
      return {
        ...state,
        [action.key]: action.result,
      };
      break;
    
    LOAD_LOCAL_DATA_FAIL:
      return {
        ...state,
        localLoadErr: action.error,
      };
      break;
    

    【讨论】: