异步action和redux-thunk

时间:2022-12-28 10:40:27

好久没写博客了,上次写还是2月份,一眨眼就过去4个月了,真是懒出翔了。- -
最近在看代码,看到一个奇怪关于redux中dispatch(action)的奇怪的用法

dispatch(fetchSkill());

export const fetchSkill = () => (dispatch, getState) => {
    dispatch(requestList());
    return getData('/api/foramis/cloudconf?id=topiclist').then(data => {
        data = data.status === 0 ? data.data.topiclist : null;
        dispatch(receiveList(data && data.reverse()));
        return data;
    }).catch(e => {});
};

代码中中dispatch了一个fetchSkill,按理来说fetchSkill返回一个有type属性的对象即可,然后再reducer中更改状态即可,这代码中的(dispatch, getState) 又是什么鬼?
后来百度了下,才知道这是redux-thunk的用法。至于redux-thunk是什么,先不说。先写个react-redux的demo

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import {createStore, applyMiddleware} from 'redux'
import {Provider} from 'react-redux'
import App from './App';
import {reducer} from './reducer'

const store = createStore(reducer)

ReactDOM.render(
    <Provider store={store}>
        <App></App>
    </Provider>,
    document.getElementById('root')
)

App.js

import React, { Component } from 'react';
import {connect} from 'react-redux'
import {click} from './action'

class App extends Component {
  render() {
    const {
      asyncText,
      dispatch
    } = this.props
    return (
      <div>
        <div>点击看看,会发生什么</div>
        <button onClick={() => dispatch(click('change after 1s'))}>点击&nbsp;</button>
        <span>{asyncText}</span>
      </div>
    );
  }
}

const mapStateToProps = (state, ownProps) => {
  return {
    asyncText: state.asyncText
  }
}
export default connect(mapStateToProps)(App);

action.js

export const click = (value) => {
    setTimeout(() => { return { type: 'ASYNC_ACTION', value } }, 1000); }

reducer.js

export function reducer (state = {asyncText: 'init'}, action) {
    switch(action.type ){
        case 'ASYNC_ACTION':
            return {
                ...state,
                asyncText: action.value
            }
        default:
            return state;
    }
}

异步action和redux-thunk

这个demo很简单,想在点击按钮后,延迟一秒更新文字。但是当我们欢快的点击完后,网页竟然报错了。
异步action和redux-thunk
这是为什么?我们似乎也没做什么出格的事,只是在action中写了个异步返回的对象。而且报错似乎提示我们要用中间件去处理异步的action。
其中的一个处理异步的中间件是redux-thunk,至于他是什么,先不说,先装上,看看能不能解决这个问题。

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import {createStore, applyMiddleware} from 'redux'
import {Provider} from 'react-redux'
import thunk from 'redux-thunk'
import App from './App';
import {reducer} from './reducer'

const middleware = [thunk]
const store = createStore(reducer,applyMiddleware(...middleware))

ReactDOM.render(
    <Provider store={store}>
        <App></App>
    </Provider>,
    document.getElementById('root')
)

action.js


export const click = (value) => (dispatch) => {
    setTimeout(() => { dispatch({ type: 'ASYNC_ACTION', value }) }, 1000); }

其他的代码不需要改
然后我们再欢快的点击按钮,1秒后
异步action和redux-thunk
看显示的结果是我们想要的,看来redux-thunk是处理异步action的一把好手

我们都知道更新Redux中状态的流程是这样的:action -> reducer -> new state。action是一个普通的javascript对象、reducer是一个普通的方法,在reducer中根据当前的state、接收到的action来生成一个新的state以达到更新状态的目的。那么问题来了,每次action被触发(dispatch),reducer就会同步地对store进行更新,在实际开发项目的时候,有很多需求都是需要通过接口等形式获取异步数据后再进行更新操作的,这时候就需要redux-thunk

原来的dispatch方法只能接收一个普通的action对象作为参数,当我们加入了ReduxThunk这个中间件之后,dispatch还可以接收一个方法作为参数,这个方法会接收到两个参数,第一个是dispatch,等同于dispatch,第二个是getState,等同于store.getState.

以上就是redux-thunk的用法。redux-thunk 帮助你统一了异步和同步 action 的调用方式,把异步过程放在 action 级别解决,对 component 没有影响。