rccoder / blog

😛 个人博客 🤐 订阅是 watch 是 watch 是 watch 是 watch
582 stars 36 forks source link

听说你需要这样了解 Redux(三) #26

Open rccoder opened 7 years ago

rccoder commented 7 years ago

Redux 异步

随着场景的复杂化,在异步结果得到之后再进行 dispatch 变得越来越不可取与不可维护。Redux 自身并没打算解决这个问题,但由于提供了 middleware,可以在这层上做文章。

比较熟知的 Redux 异步 middleware 有 redux-thunk, redux-promise, redux-saga 等。

关于这些 middlware 如何使用,可以参考我近期校对过的文章 Redux 异步四兄弟,如果怀疑文章翻译的准确度,可以直接看原文 Redux 4 ways

标准化的 action

Redux 自身没有要求 action 应该是什么格式,但按照一些实践,我们知道 action 一般包含 type 和 payload。

那如何更好的去写出标准化的 action 呢?可以看 redux-actions

如果不想仔细看 redux-actions 相关介绍,可以简单看一下我下面的介绍:

团队开发中的标准化 action

如果在多人开发中,不对 action 的设计做一定的规范,就可能会出现多种不同形式的 action,比如:


type:...|text:...

{
  type: ...,
  data: ...,
}

{
  actionType: ...,
  data: ...,
}

{
  type: ...,
  payload: ...,
}

那如何去设计一个大家可以都接受的 action 呢,在action 进化的历程中,Flux Standard Action 的设计受到广为推崇。

它约定一个 action 必须是一个对象,并且至少包含一个 key 为 type 的属性表示 action 类型。除此之外,还可以有 payload 属性表示 action 携带的数据,error 属性表示 action 是否是 “错误的”,meta 属性表示其他一些信息,当然,这只是可选的。

redux-actions 封装了一个 createAction 的函数,用它我们就能写出更加简约的 action creator,并且符合 Flux Standard Action 的标准。

以外我们写 action creator 的时候是这样:

import * as types from '../constant';

export function fetchingLogin() {
  return {
    type: types.FETCHING_LOGIN_SUCCESS,
  }
}

export function fetchingLoginSuccess(payload) {
  return {
    type: types.FETCHING_LOGIN_SUCCESS,
    payload,
  }
}

export function fetchingLoginFailure(payload) {
  return {
    type: types.FETCHING_LOGIN_FAILURE,
    payload,
    error: true,
  }
}

利用 redux-actions,我们只需要这样做:

import { createAction } from "redux-actions";
import * as types from '../constant';

export const fetchingLogin = createAction(types.FETCHING_LOGIN);
export const fetchingLoginSuccess = createAction(types.FETCHING_LOGIN_SUCCESS, data => data);
export const fetchingLoginFailure = createAction(types.FETCHING_LOGIN_FAILURE, data => data);

这样就能创建出一个非常标准化的 action 了。

同样,我们在 reducer 中依旧可以:

import * as actions from '../action';

const initState = {
  status: true,
}

export default function isLoginReducer(state = initState, action) {
  switch(action.type) {
    case actions.CHANGE_IS_LOGIN: {
      return {
        ...state,
        status: action.payload,
      }
    }
    default: {
      return state;
    }
  }
}

当然,redux-actions 提供了更简洁的 API handleActions 可以写出更加简约的 renducer:

import { handleActions } from 'redux-actions';

import * as actions from '../action';

const initState = {
  status: true,
}

const isLoginReducer = handleActions({
  [actions.changeIsLogin]: (state, action) => ({
    ...state,
    status: action.payload
  }),
}, initState);

export default isLoginReducer;

这样,教会和你合作的同学使用 redux-actions,就能写出风格一致的 action。

再也不会盯着乱七八糟的 action 喊出 WTF!

听说这是最佳实践

业界关于 redux 的实践风格已经是保持基本一致了,也就是说按照上面 Redux 4 ways 创建出了风格基本可以解决大部分的问题。

值得注意是关于 React 组件方向最好保持纯 React 组件,保持和 Redux 之间不存在耦合。和 Redux 相关的 dispatch 可以放在 container 组件中,通过在 connect 中 mapDispatchToProps 传给 container,然后调用相应的函数即可:


import { changeIsLogin } from '../../action';

const mapDispatchToProps = (dispatch, ownProps) => {
  return {
    changeIsLogin: (status) => {
      dispatch(changeIsLogin(status));
    }
  }
}

this.props.changeIsLogin(!this.props.isLogin.status)

系列文章