2

Flux Standard Action

action在Flux架构中是及其重要的概念,它是应用状态变化的必要条件,所有的状态都必须通过action触发。action的角色是状态变更信息的载体,是一个object,包含一个表示action type的字段,这是Flux对action的全部要求。不同于Flux作为架构思想的宽泛要求,在实际的开发中,我们往往希望打交道的同类实物有着类似的接口/结构。

Flux Standard Action的定位是“一个用户友好的Flux action对象标准”,它希望通过规范action的格式,为通用的action工具或抽象的实现奠定基础。换句话说,如果所有的action都有着类似的结构,那么通过统一的方法创建或修改action,或者通过统一的逻辑对action进行分析与响应等,便有了存在的可能性。

FSA结构

典型的Flux Standard Action结构如下:

{
    type: 'ADD_TODO',
    payload: {
        text: 'Do something.'
    }
}

不难发现,FSA首先是一个普通的action,鼓励我们将负载信息放到payload字段中。基于这样的初步认识,了解一下它的规范。

  • 一个action必须是一个普通的JavaScript对象,有一个type字段。
  • 一个action可能有error字段、payload字段、meta字段。
  • 一个action必须不能包含除type、payload、error及meta以外的其他字段。

type
必需字段。action的type字段标识了当前发生行为的本质特征。相同类型的行为所对应的action的type值必须是严格相等的。它往往取值为字符串常量。

payload
可选字段。可以是任意类型的数据,顾名思义,它存放当前action的“负载”内容。当error字段值为true时候,payload的值应当是一个Error对象。

error
可选字段。当取值为true时,当前action代表了某处发生了错误。

meta
可选字段。可以是任意类型的数据。用来存放非负载内容的额外信息。在Redux项目中,典型的使用meta的例子就是存放那些用来给middleware使用的信息,理论上meta的内容不会影响reducer的行为。

正如前面提到的,基于相同的action结构,提取action操作的公共逻辑会更加方便,redux-actions、redux-promise等都是在FSA基础上衍生出来的action处理工具。

redux-actions

在 redux 全家桶中,可以利用 redux-actions 来创建符合 FSA 规范的Action。我们从普通的action对象讲起。

以添加一个todo的Action为例:

{
    type:'add_todo',
    data:'我要去跑步'
}

这样就定义了一个添加一条todo的Action,然后就能通过某个行为去触发这个Action,由这个Action携带的数据(data)去更新store(state/reducer):

store.dispatch({
    type:'add_todo',
    data:'your data'
})

type 是一个常量,Action的必备字段,用于标识该Action的类型。在项目初期,这样定义Action也能愉快的撸码,但是随着项目的复杂度增加,这种方式会让代码显得冗余,因为如果有多个行为触发同一个Action,则这个Action要写多次;同时,也会造成代码结构不清晰。因而,得更改创建Action的方式:

const ADD_TODO = 'add_todo';

let addTodo = (data='default data') => {
    return {
        type: ADD_TODO,
        data: data
    }
}

//触发action
store.dispatch(addTodo());

更改之后,代码清晰多了,如果有多个行为触发同一个Action,只要调用一下函数 addTodo 就行,并将Action要携带的数据传递给该函数。类似 addTodo 这样的函数,称之为 Action Creator。Action Creator 的唯一功能就是返回一个Action供 dispatch 进行调用。

但是,这样的Action Creator 返回的Action 并不是一个标准的Action。在Flux的架构中,一个Action要符合 FSA(Flux Standard Action) 规范,需要满足如下条件:

  • 是一个纯文本对象
  • 只具备 type 、payload、error 和 meta 中的一个或者多个属性。type 字段不可缺省,其它字段可缺省
  • 若 Action 报错,error 字段不可缺省,切必须为 true

payload 是一个对象,用作Action携带数据的载体。所以,上述的写法可以更改为:

let addTodo = (data='default data') => {
    return {
        type: ADD_TODO,
        payload: {
            data
        }
    }
}

在 redux 全家桶中,可以利用 redux-actions 来创建符合 FSA 规范的Action:

import {creatAction} from 'redux-actions';

let addTodo = creatAction(ADD_TODO)
//same as
let addTodo = creatAction(ADD_TODO,data=>data)

可以采用如下一个简单的方式检验一个Action是否符合FSA标准:

let isFSA = Object.keys(action).every((item)=>{
   return  ['payload','type','error','meta'].indexOf(item) >  -1
})

zhutianxiang
1.5k 声望328 粉丝