09小斯
09小斯
3月前 · 3 人阅读

说明:对Redux不了解的同学可先看看这篇文章Redux技术架构简介(一)

前言

这里说的Redux异步实现,是专指Redux中的异步Action实现,而不是指应用的异步实现,因为Redux本身只支持同步action,即发送action,state立即更新;那如果我在发送一个action后,需要state过一段时间再更新呢?按正常的思路redux是无法处理这种情况的,下面就来看看异步Action是如何实现的吧!

需要提的一点是,其实完全可以将异步逻辑写在View中,然后在回调函数中发送action。但是如果你要配合react一起使用,这样做就违背了react-redux的设计思想,即UI与逻辑的分离(具体的实现可以在下一篇文章中看到),而且当存在多个异步请求时也很难将异步逻辑抽象出来,所以异步逻辑应该由Redux架构实现,这样也就必须实现发送异步action了

1. 中间件(Middleware)

为了解决上面提到的问题,我们需要引入中间件的概念。

(1)时机

中间件执行的时机是在action发起之后,reducer执行之前。


即在dispatch一个action之后,经过一系列的中间件处理过程,再进行reducer。

(2)原理

本质上,中间件就是对dispatch函数的改造。当执行dispatch(action)时,会先调用中间件,进行一些内部逻辑处理,如:添加日志等,之后再执行dispatch。如果要支持中间件的链式调用,必须再返回一个dispatch。
下面是中间件的简单实现:

function logger(store) {
  // 这里的 next 必须指向前一个 middleware 返回的函数:
  const next = store.dispatch

  return function dispatchAndLog(action) {
    console.log('dispatching', action)
    let result = next(action)
    console.log('next state', store.getState())
    return result
  }
}

(3) 在Redux中应用中间件

可以使用Redux的API—applyMiddleware直接使用中间件,代码如下:

import {applyMiddleware,createStore} from 'redux';
import {createLogger} from 'redux-logger';//log中间件
import thunk from 'redux-thunk';//将dispatch改造成可以接受函数作为参数的中间件
import indexPhotomainReducer from '../reducer/indexPhotomainReducer';

const logger = createLogger();
const store  = createStore(
        indexPhotomainReducer,
        applyMiddleware(thunk, logger)
);

由此可见,可以把applyMiddleware作为createStore的第二个参数传入,你所使用的中间件需要下载单独npm包,然后按顺序传入applyMiddleware函数中(注:中间件有顺序要求,需要看下每个中间件的使用文档,logger一般要放在最后)。

2. Redux异步实现

(1) Action设计

需要增加三种action

  • 通知异步请求发起的action
  • 异步请求成功的action
  • 异步请求失败的action

示例代码如下:

export const requestPostsAction = () => {
 return {
     type: REQUEST_POSTS
 };
}

export const receivePostsSuccessAction = (data) => {
 return {
     type: RECEIVE_POSTS_SUCCESS,
     data
 };
}
export const receivePostsFailureAction = (error) => {
 return {
     type: RECEIVE_POSTS_FAILURE,
     error
 };
}

返回参数完全可以自定义。这3种action分别在请求开始前,请求成功后,请求失败后发送。
## (2) State设计
为了配合异步Action,可以在state树中增加2个属性:

  • isFetching:表示是否正在处理异步请求。
  • isValidate:表示数据的有效性,他的作用是在异步请求发送失败后,告诉View当前state的数据是过时的数据。

State属性可以凭自己喜好随意设计。设计好后可以这样编写reducer:

let sliderReducer = function (state = initialState, action) {
    switch(action.type){
        case photomainAction.RECEIVE_POSTS_SUCCESS:
               return Object.assign({}, state, {photoData,videoData,isFetching:false,isValidate:true});
        case photomainAction.RECEIVE_POSTS_FAILURE:
               return Object.assign({}, state, {isFetching:false,isValidate:false});
        case photomainAction.REQUEST_POSTS:
               return Object.assign({}, state, {isFetching:true,isValidate:false});
        default:
            return state;
    }
}

(3) redux-thunk中间件

当设计好action和state后,我们想要达到的效果是--可以像同步一样dispatch一个action,而不用考虑异步逻辑。
为了达到这种效果,首先面临的问题是,异步逻辑放在哪里?这里只有2个选择:action中或reducer中(store是不适合处理数据的)。由于reducer必须是一个纯函数,他不适合处理像异步请求这样存在不确定的输出的逻辑。最后只能放在action中处理了。
这时,为了处理异步请求,action创建函数需要返回一个带有异步请求逻辑的函数,而不是一个对象了。而dispatch只能接受对象,不能接受函数作为参数,这样就面临又一个问题:如何让dispatch接受函数?
接下来就是redux-thunk中间件发挥作用的时候了,他可以让dispatch接受一个函数(原理就是上一节讲的,他其实是改写了dispatch函数),最终异步的action可以这样实现:

//定义一个action creator – fetchPosts
export const fetchPosts = () => (dispatch, getState) => {
    dispatch(requestPostsAction());
    return window.fetch("/photo/initPage").then(response=>{
            if(response.ok){
                return response.json();
            }else{
                dispatch(receivePostsFailureAction("error"));
            }
        }).then(data => {
            if(data){
                dispatch(receivePostsSuccessAction(data));
            }else{
                dispatch(receivePostsFailureAction("error"));
            }
        });
}

这样就可以像同步一样发送action了,即:

dispatch(fetchPosts());

接下来只需静静等待view的更新就行了,这样就实现了整个Redux的异步流程。

本篇到此告一段落,下一篇介绍React与Redux整合技术

参考

Redux 中文文档
Redux 入门教程-阮一峰

收藏 0
redux javascript react.js
评论 ( 0 )