diff --git a/CHANGELOG.md b/CHANGELOG.md index d701585..660dbd2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,25 @@ # CHANGELOG +## 2.0.0 (2018-04-??) + +### Feature and Breaking change + ++ Rename `CirquitAction` to `Operation` ([#8](https://github.com/airtoxin/redux-cirquit/pull/8)) + +This change only affect to createCirquitAction method's name. + +__before__ + +```js +createCirquitAction(/* any arguments */); +``` + +__after__ + +```js +createOperation(/* any arguments */); +``` + ## 1.4.0 (2018-04-05) ### Features diff --git a/README.md b/README.md index f937c22..aec58f2 100644 --- a/README.md +++ b/README.md @@ -1,34 +1,34 @@ # redux-cirquit [![Build Status](https://travis-ci.org/airtoxin/redux-cirquit.svg?branch=master)](https://travis-ci.org/airtoxin/redux-cirquit) -__Realize command based short-circuiting redux.__ +__To realize operation based short-circuiting redux.__ ## Concept -The aim of redux-cirquit is to realize command based application system on redux ecosystem. +The aim of redux-cirquit is to realize operation based application system on redux ecosystem. Redux is an implementation of Flux based on __event based__ application system. Its concept is good but bit tired, -because event system requires to define event elements separately each other (eventName, eventPublisher, eventSubscriber) to keep loose-coupling between eventPublisher and eventSubscriber. +because event system requires to define event elements separately each other (EventName, EventPublisher, EventSubscriber) to keep loose-coupling between event publisher and subscriber. -Event based application system is suitable for large sized application, but overkill for small-medium sized application. -And we almost define its event elements tight-coupled. -Tight-couped event system is nearly equals to __command based__ application system. -If you use redux with command based application system, there are no reason to define event elements separately (actionTypes, action, actionCreator and reducer). +Event based application system is suitable for gigantic large sized application, but overkill for small or medium sized application. +And we almost define its event elements (event publisher and subscriber) tight-coupled. +Tight-couped event system is nearly equals to __operation based__ application system. +If you use redux with operation based application system, there are no reason to define event elements separately (ActionTypes, Action, ActionCreator and Reducer). -Command based application system is much simpler than event based. -There is only exists "command", so your actionCreator (with dispatch) is called as command. +Operation based application system is much simpler than event based. +There is only exists "Operation", so your ActionCreator (with dispatch) is called as operation. This is a redux-cirquit. ```js -const increment = amount => createCirquitAction(state => ({ +const increment = amount => createOperation(state => ({ ...state, counter: { count: state.counter.count + amount } })); -// execute increment command +// execute increment operation store.dispatch(increment(1)); ``` @@ -40,7 +40,7 @@ store.dispatch(increment(1)); ```js import { createStore } from "redux"; -import { createCirquitReducer, createCirquitAction } from "redux-cirquit"; +import { createCirquitReducer, createOperation } from "redux-cirquit"; const initialState = { counter: { @@ -50,7 +50,7 @@ const initialState = { const cirquitReducer = createCirquitReducer(initialState); const store = createStore(cirquitReducer); -const increment = amount => createCirquitAction(state => ({ +const increment = amount => createOperation(state => ({ ...state, counter: { count: state.counter.count + amount @@ -68,7 +68,7 @@ const store = createStore(combineReducers({ user: createCirquitReducer(initialUserState, { namespace: "user" }) })); -const increment = amount => createCirquitAction(state => ({ +const increment = amount => createOperation(state => ({ ...state, count: state.count + amount }), { namespace: "counter" }); @@ -82,24 +82,31 @@ store.dispatch(increment(1)); ### export createCirquitReducer\(initialState: State, options?: { namespace?: string }): Redux.Reducer\ -Creates redux-cirquit's reducer that manages your application's state. -If you want to split reducer using `combineReducers`, you must specify reducer name by `namespace` option. +Creates redux-cirquit's reducer. +If you want to split reducer using `combineReducers`, you should specify `namespace` in option. -### export createCirquitAction\(reducer: (state: State) => State, options?: CirquitActionOptions }): Redux.Action +### export createOperation\(reducer: (s: State) => State, options?: OperationOptions }): Redux.Action -Creates basic redux action to reduce you application's state. +Creates operation to reduce state. +The operation is actually redux's action. -#### CirquitActionOptions = { namespace?: string, meta?: { reducerName?: string, ...anyProps } } +#### OperationOptions = { namespace?: string, meta?: { reducerName?: string, ...anyProps } } -If you use splited reducer, must set same `namespace` of related reducer to this action. +If you use splitted reducer, you should set same `namespace` of reducer related to this action. `meta` properties is almostly pass through to returned action's meta property except `meta.reducerName` property, so you can define any debugging informations in `meta`. `meta.reducerName` is optional property to define action name. If not specify `meta.reducerName`, [function name](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name) or "anonymous" is used. +### getActionType(namespace: string): string + +Get action type used in redux-cirquit internally. + ## Articles [それでもやっぱり redux は面倒くさい](https://qiita.com/airtoxin/items/1632d523ad95adf6f3fe) (Japanese) +## [Changelog](/CHANGELOG.md) + ## License MIT diff --git a/src/index.spec.ts b/src/index.spec.ts index f1c39f6..8638057 100644 --- a/src/index.spec.ts +++ b/src/index.spec.ts @@ -1,8 +1,8 @@ import "jest"; import { - getCirquitActionType, + getActionType, createCirquitReducer, - createCirquitAction, + createOperation, CirquitReducer } from "./index"; import { createStore, Dispatch } from "redux"; @@ -21,13 +21,13 @@ const initialState: State = { const noopReducer: CirquitReducer = state => state; -const incrementActionWithoutNamespace = createCirquitAction(state => ({ +const incrementActionWithoutNamespace = createOperation(state => ({ counter: { count: state.counter.count + 1 } })); -const incrementActionWithNamespace = createCirquitAction( +const incrementActionWithNamespace = createOperation( state => ({ counter: { count: state.counter.count + 1 @@ -37,9 +37,9 @@ const incrementActionWithNamespace = createCirquitAction( ); describe("interface between redux", () => { - it("createCirquitAction should return redux action", () => { + it("createOperation should return redux action", () => { const dispatch = jest.fn>(); - const action = createCirquitAction(noopReducer); + const action = createOperation(noopReducer); // type checking dispatch(action); // dummy assertion @@ -54,10 +54,10 @@ describe("interface between redux", () => { }); }); -describe("createCirquitAction", () => { - it("should return cirquitAction", () => { - expect(createCirquitAction(noopReducer)).toEqual({ - type: getCirquitActionType(), +describe("createOperation", () => { + it("should return operation action", () => { + expect(createOperation(noopReducer)).toEqual({ + type: getActionType(), meta: { reducerName: "noopReducer" }, @@ -70,7 +70,7 @@ describe("createCirquitAction", () => { describe("meta option", () => { it("should pass through meta options to action meta", () => { const meta = { a: "a", b: "b" }; - expect(createCirquitAction(noopReducer, { meta }).meta).toEqual({ + expect(createOperation(noopReducer, { meta }).meta).toEqual({ ...meta, reducerName: "noopReducer" }); @@ -79,14 +79,14 @@ describe("createCirquitAction", () => { describe("reducerName option", () => { it("should be anonymous when reducer is arrow function", () => { - expect(createCirquitAction(state => state).meta.reducerName).toBe( + expect(createOperation(state => state).meta.reducerName).toBe( "anonymous" ); }); it("should be anonymous when reducer is anonymous function", () => { expect( - createCirquitAction(function(state: State) { + createOperation(function(state: State) { return state; }).meta.reducerName ).toBe("anonymous"); @@ -94,14 +94,14 @@ describe("createCirquitAction", () => { it("should named by inferred arrow function", () => { const namedReducer = (state: State) => state; - expect(createCirquitAction(namedReducer).meta.reducerName).toBe( + expect(createOperation(namedReducer).meta.reducerName).toBe( "namedReducer" ); }); it("should named by named function", () => { expect( - createCirquitAction(function namedReducer(state: State) { + createOperation(function namedReducer(state: State) { return state; }).meta.reducerName ).toBe("namedReducer"); @@ -110,7 +110,7 @@ describe("createCirquitAction", () => { it("should named when invoked with reducerName option", () => { const namedReducer = (state: State) => state; expect( - createCirquitAction(namedReducer, { + createOperation(namedReducer, { meta: { reducerName: "nameParams" } }).meta.reducerName ).toBe("nameParams"); @@ -120,8 +120,8 @@ describe("createCirquitAction", () => { describe("namespace option", () => { it("should be namespace defined action when specified namespace option", () => { expect( - createCirquitAction(noopReducer, { namespace: "my-namespace" }).type - ).toBe("@@cirquit/action/my-namespace"); + createOperation(noopReducer, { namespace: "my-namespace" }).type + ).toBe("@@cirquit/my-namespace"); }); }); }); diff --git a/src/index.ts b/src/index.ts index 5a2a4ce..cc4882a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,36 +1,36 @@ import { Action, AnyAction, Reducer } from "redux"; -export const getCirquitActionType = (namespace: string = "") => - `@@cirquit/action/${namespace}`; +export const getActionType = (namespace: string = "") => + `@@cirquit/${namespace}`; export interface CirquitReducer { (state: State): State; name?: string; } -export interface CirquitActionMeta { +export interface OperationMeta { reducerName?: string; [key: string]: any; } -export interface CirquitAction extends Action { +export interface Operation extends Action { type: string; - meta: CirquitActionMeta; + meta: OperationMeta; payload: { reducer: CirquitReducer; }; } -export interface CirquitActionOptions { +export interface OperationOptions { namespace?: string; - meta?: CirquitActionMeta; + meta?: OperationMeta; } -export const createCirquitAction = ( +export const createOperation = ( reducer: CirquitReducer, - options: CirquitActionOptions = {} -): CirquitAction => ({ - type: getCirquitActionType(options.namespace), + options: OperationOptions = {} +): Operation => ({ + type: getActionType(options.namespace), meta: { ...options.meta, reducerName: @@ -50,11 +50,11 @@ export const createCirquitReducer = ( options: CirquitReducerOptions = {} ): Reducer => ( state: State = initialState, - action: AnyAction /* Use temporal AnyAction instead of CirquitAction https://github.com/Microsoft/TypeScript/issues/16795 */ + action: AnyAction /* Use temporal AnyAction instead of Operation https://github.com/Microsoft/TypeScript/issues/16795 */ ): State => { switch (action.type) { - case getCirquitActionType(options.namespace): { - return (action as CirquitAction).payload.reducer(state); + case getActionType(options.namespace): { + return (action as Operation).payload.reducer(state); } default: { return state;