dispatch作用 react_打入react&redux(2)- 神秘的dispatch

action中dispatch的使用疑惑

当在项目中createStore时applyMiddleware了redux-thunk的thunkMiddleware后,action里的dispatch就变得很魔性,加也可以,不加也可以,譬如以下2种写法都能达到预期的效果。

export function fetchPosts(reddit) {

return {

type: REQUEST_POSTS,

reddit

}

}

或者

export function fetchPosts(reddit) {

return dispatch => {

return dispatch({

type: REQUEST_POSTS,

reddit

})

}

}

那么在派发action的函数里用dispatch和不使用dispatch有什么区别

从函数调用栈挖出dispatch干了啥

情形1:return dispatch(action)

先看加了dispatch的函数调用栈

export function fetchPosts(reddit) {

return dispatch => {

return dispatch({

type: REQUEST_POSTS,

reddit

})

}

}

按图中标注我们来看看每个核心步骤都在干什么。

view层调用dispatch分发action

componentDidMount() {

const { dispatch, selectedReddit } = this.props

dispatch(fetchPostsIfNeeded(selectedReddit)) //执行点

}

进入thunkMiddleware

function thunkMiddleware(_ref) {

var dispatch = _ref.dispatch;

var getState = _ref.getState;

return function (next) {

return function (action) {

return typeof action === 'function' ? action(dispatch, getState) : next(action); // 执行点,action为

};

}

这个函数在全过程中执行了2次,这一次执行时,action的值为:

dispatch => {

return dispatch({

type: REQUEST_POSTS,

reddit

})

}

};

可见action为一个函数,thunkMiddleware将dispatch和getState方法注入到这个函数中并执行该函数。

return dispatch(action)。

export function fetchPostsIfNeeded(reddit) {

return dispatch => {

return dispatch({ //执行点

type: REQUEST_POSTS,

reddit

})

}

}

进入applyMiddleware中执行封装的供中间件使用的dispatch方法。

function applyMiddleware() {

for (var _len = arguments.length, middlewares = Array(_len), _key = 0; _key < _len; _key++) {

middlewares[_key] = arguments[_key];

}

return function (createStore) {

return function (reducer, initialState, enhancer) {

var store = createStore(reducer, initialState, enhancer);

var _dispatch = store.dispatch;

var chain = [];

var middlewareAPI = {

getState: store.getState,

dispatch: function dispatch(action) {

return _dispatch(action); //执行点

}

};

chain = middlewares.map(function (middleware) {

return middleware(middlewareAPI);

});

_dispatch = _compose2["default"].apply(undefined, chain)(store.dispatch);

return _extends({}, store, {

dispatch: _dispatch

});

};

};

}

同2中一致,再次进入thunkMiddleware,这次action为action对象,将直接调用next(action):

{

type: REQUEST_POSTS,

reddit

}

这是因为加了redux-logger,调用redux-logger中间件处理

真正执行store中的dispatch函数,并去调用currentReducer获取已最新的state状态。以下是redux中createStore.js里dispatch方法的源码。

function dispatch(action) {

if (!(0, _isPlainObject2["default"])(action)) {

throw new Error('Actions must be plain objects. ' + 'Use custom middleware for async actions.');

}

if (typeof action.type === 'undefined') {

throw new Error('Actions may not have an undefined "type" property. ' + 'Have you misspelled a constant?');

}

if (isDispatching) {

throw new Error('Reducers may not dispatch actions.');

}

try {

isDispatching = true;

currentState = currentReducer(currentState, action); //执行点

} finally {

isDispatching = false;

}

var listeners = currentListeners = nextListeners;

for (var i = 0; i < listeners.length; i++) {

listeners[i]();

}

return action;

}

combineReducer将action分发到相应的reducer的state分支进行更新。

reducer中更新state

function postsByReddit(state = { }, action) {

switch (action.type) {

case INVALIDATE_REDDIT:

case RECEIVE_POSTS:

case REQUEST_POSTS:

return Object.assign({}, state, {

[action.reddit]: posts(state[action.reddit], action)

})

default:

return state

}

}

情形二:直接return action

这种使用方式会从1直接执行到5,没有thunkMiddleware中调用action(dispatch, getState)一步,因为action不是一个函数,只是一个对象。也不会执行applyMiddleware中封装的dispacth方法。

dispatch解密

从以上函数调用栈的追踪可以解开dispatch的谜团了。

dispatch分为2种:

type BaseDispatch = (a: Action) => Action,由redux createStore.js提供的store.dispatch。处理结果返回action对象

type Dispatch = (a: Action

AsyncAction) => any,由applyMiddleware封装的能够处理同步action和异步action的函数,并将返回值传递给其他中间件使用。他的返回值类型没有任何限制。

Base dispatch function 总是同步地把 action 与上一次从 store 返回的 state 发往 reducer,然后计算出新的 state。它期望 action 会是一个可以被 reducer 消费的普通对象。

Middleware 封装了 base dispatch function,允许 dispatch function 处理 普通action 之外的异步 action。 Middleware 可以改变、延迟、忽略 action 或异步 action,也可以在传递给下一个 middleware 之前对它们进行解释。

上述例子中的情形一就是调用了Middleware封装的dispacth对action做了处理(虽然我没有真的写处理代码),而情形二是直接调用store实例的base dispatch.

action creator

这里要引入action creator的概念。

Action Creator 就是一个创建 action 的函数。Action 是一个信息的负载,而 action creator 是一个创建 action 的工厂。

调用 action creator 只会生产 action,但不分发。还需要调用 store 的 dispatch function 才会引起变化。

什么时候要在action creator调用dispatch

如果 action creator 需要读取当前的 state、调用 API、或引起诸如路由变化等副作用,那么它应该返回一个异步 action而不是 action。这时候就应该使用Middleware封装的dispacth了。

最常见的2种情形:

需要获取state,通过读取state的内容结合view层传过来的参数生成action的内容,就需要使用Middleware封装的方法,得到getState接口来获得state,然后dispatch action

function actionCreator(params) {

(dispatch, getState) => {

let state = getState();

//获取state内容,并结合params等进行逻辑处理

return dispatch({

type: types.TEST

data: data

})

}

}

异步action。譬如需要异步请求的结果作为action的内容,需要和Promise搭配使用等。

function fetchData(data){

fetch(url, {

body: data

})

.then((response) => {

if(response.status >= 200 && response.status < 300){

return response.json()

} else {

message.error("服务器错误,请联系技术哥哥");

}

})

.then((response) => {

return new Promise((resolve, reject) => {

response && resolve(response);

})

})

.catch(()=>{

errorCallback();

});

}

export function asynchronousActionCreator(params){

return (dispatch, getState) => {

let promiseRes;

promiseRes = fetchData(params); // fetchData函数返回的是promise对象

if(promiseRes && promiseRes.then){

promiseRes.then((data)=>{

return dispatch({

type: types.CHANGE_DATA,

data: data

})

});

}

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值