github路徑:https://github.com/pauldijou/…
這是一個自用的工具用於建立actions
和reducers
用於redux
。主要的目標是使用action
本身作為reducer
的引用而不是變數。
安裝
npm install redux-act --save
用法
這裡有一個名叫createAction
的函式,它用於建立一個action
,和名叫createActionCreator
的方法有點接近。如果你不能確定是否是action
或action
創造者,那麼記住當action
創造者是方法時,action
是物件。
// Import functions
import { createStore } from `redux`;
import { createAction, createReducer } from `redux-act`;
// Create an action creator (description is optional)
const add = createAction(`add some stuff`);
const increment = createAction(`increment the state`);
const decrement = createAction(`decrement the state`);
// Create a reducer
// (ES6 syntax, see Advanced usage below for an alternative for ES5)
const counterReducer = createReducer({
[increment]: (state) => state + 1,
[decrement]: (state) => state - 1,
[add]: (state, payload) => state + payload,
}, 0); // <-- This is the default state
// Create the store
const counterStore = createStore(counterReducer);
// Dispatch actions
counterStore.dispatch(increment()); // counterStore.getState() === 1
counterStore.dispatch(increment()); // counterStore.getState() === 2
counterStore.dispatch(decrement()); // counterStore.getState() === 1
counterStore.dispatch(add(5)); // counterStore.getState() === 6
高階用法
import { createStore } from `redux`;
import { createAction, createReducer } from `redux-act`;
// You can create several action creators at once
// (but that`s probably not the best way to do it)
const [increment, decrement] = [`inc`, `dec`].map(createAction);
// When creating action creators, the description is optional
// it will only be used for devtools and logging stuff.
// It`s better to put something but feel free to leave it empty if you want to.
const replace = createAction();
// By default, the payload of the action is the first argument
// when you call the action. If you need to support several arguments,
// you can specify a function on how to merge all arguments into
// an unique payload.
let append = createAction(`optional description`, (...args) => args.join(``));
// There is another pattern to create reducers
// and it works fine with ES5! (maybe even ES3 o/)
const stringReducer = createReducer(function (on) {
on(replace, (state, payload) => payload);
on(append, (state, payload) => state += payload);
// Warning! If you use the same action twice,
// the second one will override the previous one.
}, `missing a lette`); // <-- Default state
// Rather than binding the action creators each time you want to use them,
// you can do it once and for all as soon as you have the targeted store
// assignTo: mutates the action creator itself
// bindTo: returns a new action creator assigned to the store
const stringStore = createStore(stringReducer);
replace.assignTo(stringStore);
append = append.bindTo(stringStore);
// Now, when calling actions, they will be automatically dispatched
append(`r`); // stringStore.getState() === `missing a letter`
replace(`a`); // stringStore.getState() === `a`
append(`b`, `c`, `d`); // stringStore.getState() === `abcd`
// If you really need serializable actions, using string constant rather
// than runtime generated id, just use a uppercase description (with eventually some underscores)
// and it will be use as the id of the action
const doSomething = createAction(`STRING_CONSTANT`);
doSomething(1); // { type: `STRING_CONSTANT`, payload: 1}
// Little bonus, if you need to support metadata around your action,
// like needed data but not really part of the payload, you add a second function
const metaAction = createAction(`desc`, arg => arg, arg => ({meta: `so meta!`}));
// Metadata will be the third argument of the reduce function
createReducer({
[metaAction]: (state, payload, meta) => payload
});
API說明
createAction([description], [payloadReducer], [metaReducer])
引數
-
description(字串,可選) 當顯示的時候用於註冊action名稱和在開發者工具中使用。如果這個引數只是大寫,它可以在不用生成任何id的情況下被用作
action
型別。你可以使用這個特性在服務端和客戶端中有序整理action
。 -
payloadReducer(方法,可選) 轉變多個引數作為唯一的
payload
。 -
metaReducer(方法,可選) 轉變多個引數作為唯一的後設資料物件。
用法
返回一個新的action
構造器。如果你指定了description
,它將被開發者工具使用。預設情況下,createAction
返回一個方法,並且觸發它的時候第一個引數被作為payload
。如果你想支援多個引數,你需要指定一個payloadReducer
來把所有的引數合併到payload
中。
// Super simple action
const simpleAction = createAction();
// Better to add a description
const betterAction = createAction(`This is better!`);
// Support multiple arguments by merging them
const multipleAction = createAction((text, checked) => ({text, checked}))
// Again, better to add a description
const bestAction = createAction(`Best. Action. Ever.`, (text, checked) => ({text, checked}))
// Serializable action (the description will be used as the unique identifier)
const serializableAction = createAction(`SERIALIZABLE_ACTION`);
action creator
action
創造器基本上是一個攜帶引數並且返回action
的方法,它具有以下格式:
-
type:通過引數
description
生成id -
payload:當呼叫
action creator
時進行資料傳遞,傳遞的是第一個引數除非在建立action
時指定了payloadReducer
. -
meta:如果你提供了
metaReducer
,它將建立一個metadata
物件分配給這個key
,否則它是undefined
const addTodo = createAction(`Add todo`);
addTodo(`content`);
// return { type: `[1] Add todo`, payload: `content` }
const editTodo = createAction(`Edit todo`, (id, content) => ({id, content}));
editTodo(42, `the answer`);
// return { type: `[2] Edit todo`, payload: {id: 42, content: `the answer`} }
const serializeTodo = createAction(`SERIALIZE_TODO`);
serializeTodo(1);
// return { type: `SERIALIZE_TODO`, payload: 1 }
action creator
有以下方法:
getType()
返回生成的型別並被用於這個action creator
的所有action
。
assignTo(store | dispatch)
記住你要觸發這些actions
,如果你有一個或多個stores
,可以通過assignTo
分配這些action
。這會改變action creator
本身,你可以傳遞一個store
或者dispatch
方法或者陣列。
let action = createAction();
let action2 = createAction();
const reducer = createReducer({
[action]: (state) => state * 2,
[action2]: (state) => state / 2,
});
const store = createStore(reducer, 1);
const store2 = createStore(reducer, -1);
// Automatically dispatch the action to the store when called
action.assignTo(store);
action(); // store.getState() === 2
action(); // store.getState() === 4
action(); // store.getState() === 8
// You can assign the action to several stores using an array
action.assignTo([store, store2]);
action();
// store.getState() === 16
// store2.getState() === -2
bindTo(store | dispatch)
如果你需要不可變,你可以使用該方法。它將生成一個新的action creator
並且能夠自動觸發action
。
// If you need more immutability, you can bind them, creating a new action creator
const boundAction = action2.bindTo(store);
action2(); // Not doing anything since not assigned nor bound
// store.getState() === 16
// store2.getState() === -2
boundAction(); // store.getState() === 8
assigned() / bound() / dispatched()
測試action creator
的當前狀態。
const action = createAction();
action.assigned(); // false, not assigned
action.bound(); // false, not bound
action.dispatched(); // false, test if either assigned or bound
const boundAction = action.bindTo(store);
boundAction.assigned(); // false
boundAction.bound(); // true
boundAction.dispatched(); // true
action.assignTo(store);
action.assigned(); // true
action.bound(); // false
action.dispatched(); // true
raw(…args)
當action creator
無論是分配還是繫結,將不再返回action
物件而是觸發它。有些情況下,你需要沒有觸發的action
。為了達到這個目的,你可以使用raw
方法返回純粹的action
。
const action = createAction().bindTo(store);
action(1); // store has been updated
action.raw(1); // return the action, store hasn`t been updated
createReducer(handlers, [defaultState])
引數
-
handlers(物件或方法):如果是方法則攜帶兩個屬性,一是註冊
action
,二是取消註冊,如下。 -
defaultState(任意,可選):
reducer
的初始狀態,如果要在combineReducers
使用千萬不能為空。
用法
返回一個新的reducer
。和Array.prototype.reduce
的語法類似,你可以指定如何累加,比如第一個引數並累加,或者預設的狀態。預設的狀態是可選的,因為建立時可以在store
中獲取,但你需要注意reducer
中始終存在預設狀態,尤其是你要結合combineReducers
使用時。
有兩種建立reducer
的方式,一種是通過物件集合,所有方法必須遵循previousState, payload) => newState
。另一種是使用工廠模式,話不多說,看下面的例子。
const increment = createAction();
const add = createAction();
// First pattern
const reducerMap = createReducer({
[increment]: (state) => state + 1,
[add]: (state, payload) => state + payload
}, 0);
// Second pattern
const reducerFactory = createReducer(function (on, off) {
on(increment, (state) => state + 1);
on(add, (state, payload) => state + payload);
// `off` remove support for a specific action
// See `Adding and removing actions` section
}, 0);
reducer
reducer
就是一個方法。它當前的狀態和行為並返回新的狀態,有以下方法:
options(object)
因為action
是帶有type
、payload
甚至還有metadata
的物件。所有的reduce
方法預設將payload
作為它們的第二個引數,metadata
作為第三個引數,而不是所有的action
。因為所有其他屬性由lib處理不用關心。如果你要使用全部的action
,你可以改變reducer
的行為。
const add = createAction();
const sub = createAction();
const reducer = createReducer({
[add]: (state, action) => state + action.payload,
[sub]: (state, action) => state - action.payload
}, 0);
reducer.options({
payload: false
});
has(action creator)
檢測reducer
是否含有reduce
方法對於特定的action
或者字串型別。
const add = createAction();
const sub = createAction();
const reducer = createReducer({
[add]: (state, action) => state + action.payload
}, 0);
reducer.has(add); // true
reducer.has(sub); // false
reducer.has(add.getType()); // true
on(action creator, reduce function) / off(action creator)
可以動態新增或刪除action。
assignAll(actionCreators, stores)
引數
-
actionCreators(物件或陣列)
-
stores(物件或陣列)
用法
普遍的方式是匯出一系列的action作為物件,如果你需要將所有繫結到store,這裡有一個超級小幫手。也可以使用action陣列。
// actions.js
export const add = createAction(`Add`);
export const sub = createAction(`Sub`);
// reducer.js
import * as actions from `./actions`;
export default createReducer({
[actions.add]: (state, payload) => state + payload,
[actions.sub]: (state, payload) => state - payload
}, 0);
// store.js
import * as actions from `./actions`;
import reducer from `./reducer`;
const store = createStore(reducer);
assignAll(actions, store);
export default store;
bindAll(actionCreators, stores)
引數
-
actionCreators(物件或陣列)
-
stores(物件或陣列)
用法
類似於assignAll
,可以立刻繫結action
。
import { bindAll } from `redux-act`;
import store from `./store`;
import * as actions from `./actions`;
export bindAll(actions, store);
disbatch(store | dispatch, [actions])
引數
-
store | dispatch (物件,store或diaptch方法),在
store
上新增disbatch
方法,類似於diaptch
,但這個是觸發多個action
。 -
actions(陣列,可選) 需要觸發的一些
action
用法
// All samples will display both syntax with and without an array
// They are exactly the same
import { disbatch } from `redux-act`;
import { inc, dec } from `./actions`;
// Add `disbatch` directly to the store
disbatch(store);
store.disbatch(inc(), dec(), inc());
store.disbatch([inc(), dec(), inc()]);
// Disbatch immediately from store
disbatch(store, inc(), dec(), inc());
disbatch(store, [inc(), dec(), inc()]);
// Disbatch immediately from dispatch
disbatch(store.dispatch, inc(), dec(), inc());
disbatch(store.dispatch, [inc(), dec(), inc()]);