feat: allow adding actionCreators via addAction()

This commit is contained in:
Yanick Champoux 2020-02-01 12:46:29 -05:00
commit 27ae46dbab
4 changed files with 87 additions and 28 deletions

View File

@ -283,7 +283,9 @@ store.dispatch.addTodo(...);
store.dispatch( actions.addTodo(...) ); store.dispatch( actions.addTodo(...) );
``` ```
## asDux ## Methods
### asDux
Returns a [ducks](https://github.com/erikras/ducks-modular-redux)-like Returns a [ducks](https://github.com/erikras/ducks-modular-redux)-like
@ -291,7 +293,7 @@ plain object holding the reducer from the Updux object and all
its trimmings. its trimmings.
## addMutation ### addMutation
Adds a mutation and its associated action to the updux. Adds a mutation and its associated action to the updux.
If a local mutation was already associated to the action, If a local mutation was already associated to the action,
@ -303,3 +305,30 @@ conditionally run the subduxes mutations, check out [[subduxUpreducer]].
```js ```js
updux.addMutation( add, inc => state => state + inc ); updux.addMutation( add, inc => state => state + inc );
``` ```
### addAction
```js
const action = updux.addAction( name, ...creatorArgs );
const action = updux.addAction( otherActionCreator );
```
Adds an action to the updux. It can take an already defined action creator,
or any arguments that can be passed to `actionCreator`.
```js
import {actionCreator, Updux} from 'updux';
const updux = new Updux();
const foo = updux.addAction('foo');
const bar = updux.addAction( 'bar', (x) => ({stuff: x+1}) );
const baz = actionCreator( 'baz' );
foo({ a: 1}); // => { type: 'foo', payload: { a: 1 } }
bar(2); // => { type: 'bar', payload: { stuff: 3 } }
baz(); // => { type: 'baz', payload: undefined }
```

View File

@ -1,38 +1,65 @@
import Updux from "."; import Updux, {actionCreator} from '.';
import u from "updeep"; import u from 'updeep';
const noopEffect = () => () => () => {}; const noopEffect = () => () => () => {};
test.only("actions defined in effects and mutations, multi-level", () => { test('actions defined in effects and mutations, multi-level', () => {
const { actions } = new Updux({ const {actions} = new Updux({
effects: { effects: {
foo: noopEffect foo: noopEffect,
}, },
mutations: { bar: () => () => null }, mutations: {bar: () => () => null},
subduxes: { subduxes: {
mysub: { mysub: {
effects: { baz: noopEffect }, effects: {baz: noopEffect},
mutations: { quux: () => () => null }, mutations: {quux: () => () => null},
actions: { actions: {
foo: (limit: number) => ({ limit }) foo: (limit: number) => ({limit}),
} },
}, },
myothersub: { myothersub: {
effects: { effects: {
foo: noopEffect foo: noopEffect,
} },
} },
} },
}); });
const types = Object.keys(actions); const types = Object.keys(actions);
types.sort(); types.sort();
expect(types).toEqual(["bar", "baz", "foo", "quux"]); expect(types).toEqual(['bar', 'baz', 'foo', 'quux']);
expect(actions.bar()).toEqual({ type: "bar" }); expect(actions.bar()).toEqual({type: 'bar'});
expect(actions.bar("xxx")).toEqual({ type: "bar", payload: "xxx" }); expect(actions.bar('xxx')).toEqual({type: 'bar', payload: 'xxx'});
expect(actions.bar(undefined, "yyy")).toEqual({ type: "bar", meta: "yyy" }); expect(actions.bar(undefined, 'yyy')).toEqual({type: 'bar', meta: 'yyy'});
expect(actions.foo(12)).toEqual({ type: "foo", payload: { limit: 12 } }); expect(actions.foo(12)).toEqual({type: 'foo', payload: {limit: 12}});
});
describe('different calls to addAction', () => {
const updux = new Updux();
test('string', () => {
updux.addAction('foo');
expect(updux.actions.foo('yo')).toMatchObject({
type: 'foo',
payload: 'yo',
});
});
test('actionCreator', () => {
const bar = actionCreator('bar', null);
updux.addAction(bar);
expect(updux.actions.bar()).toMatchObject({
type: 'bar',
});
});
test('actionCreator inlined', () => {
updux.addAction('baz', (x) => ({x}));
expect(updux.actions.baz(3)).toMatchObject({
type: 'baz', payload: { x: 3 }
});
});
}); });

View File

@ -21,7 +21,7 @@ import {
EffectEntry EffectEntry
} from "./types"; } from "./types";
import { Middleware, Store } from "redux"; import { Middleware, Store, PreloadedState } from "redux";
export { actionCreator } from "./buildActions"; export { actionCreator } from "./buildActions";
type StoreWithDispatchActions< type StoreWithDispatchActions<
@ -129,7 +129,7 @@ export class Updux<S = any> {
return buildCreateStore<S>( return buildCreateStore<S>(
this.reducer, this.reducer,
this.initial, this.initial as PreloadedState<S>,
this.middleware as any, this.middleware as any,
actions actions
) as () => StoreWithDispatchActions<S, typeof actions>; ) as () => StoreWithDispatchActions<S, typeof actions>;
@ -175,14 +175,17 @@ export class Updux<S = any> {
this.localEffects.push([c.type, middleware, isGenerator]); this.localEffects.push([c.type, middleware, isGenerator]);
} }
addAction(action: string | ActionCreator<any>) { addAction(action: string, transform?: any): ActionCreator<string,any>
addAction(action: ActionCreator<any>, transform?: never): ActionCreator<string,any>
addAction(action: any,transform:any) {
if (typeof action === "string") { if (typeof action === "string") {
if (!this.localActions[action]) { if (!this.localActions[action]) {
this.localActions[action] = actionFor(action); this.localActions[action] = actionCreator(action,transform);
} }
} else { return this.localActions[action];
this.localActions[action.type] = action;
} }
return this.localActions[action.type] = action;
} }
get _middlewareEntries() { get _middlewareEntries() {

View File

@ -27,7 +27,7 @@
/* Strict Type-Checking Options */ /* Strict Type-Checking Options */
"strict": true, /* Enable all strict type-checking options. */ "strict": true, /* Enable all strict type-checking options. */
"noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ "noImplicitAny": false, /* Raise error on expressions and declarations with an implied 'any' type. */
// "strictNullChecks": true, /* Enable strict null checks. */ // "strictNullChecks": true, /* Enable strict null checks. */
// "strictFunctionTypes": true, /* Enable strict checking of function types. */ // "strictFunctionTypes": true, /* Enable strict checking of function types. */
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */