diff --git a/docs/API/assets/search.js b/docs/API/assets/search.js index aaea63e..02b53f8 100644 --- a/docs/API/assets/search.js +++ b/docs/API/assets/search.js @@ -1 +1 @@ -window.searchData = {"kinds":{"4":"Namespace","128":"Class","256":"Interface","512":"Constructor","1024":"Property","262144":"Accessor","4194304":"Type alias"},"rows":[{"id":0,"kind":4194304,"name":"Dict","url":"modules.html#Dict","classes":"tsd-kind-type-alias tsd-has-type-parameter"},{"id":1,"kind":4,"name":"\"updux\"","url":"modules/_updux_.html","classes":"tsd-kind-namespace"},{"id":2,"kind":256,"name":"UpduxConfig","url":"interfaces/_updux_.UpduxConfig.html","classes":"tsd-kind-interface tsd-parent-kind-namespace tsd-has-type-parameter","parent":"\"updux\""},{"id":3,"kind":1024,"name":"initial","url":"interfaces/_updux_.UpduxConfig.html#initial","classes":"tsd-kind-property tsd-parent-kind-interface","parent":"\"updux\".UpduxConfig"},{"id":4,"kind":1024,"name":"subduxes","url":"interfaces/_updux_.UpduxConfig.html#subduxes","classes":"tsd-kind-property tsd-parent-kind-interface","parent":"\"updux\".UpduxConfig"},{"id":5,"kind":1024,"name":"actions","url":"interfaces/_updux_.UpduxConfig.html#actions","classes":"tsd-kind-property tsd-parent-kind-interface","parent":"\"updux\".UpduxConfig"},{"id":6,"kind":1024,"name":"selectors","url":"interfaces/_updux_.UpduxConfig.html#selectors","classes":"tsd-kind-property tsd-parent-kind-interface","parent":"\"updux\".UpduxConfig"},{"id":7,"kind":1024,"name":"mutations","url":"interfaces/_updux_.UpduxConfig.html#mutations","classes":"tsd-kind-property tsd-parent-kind-interface","parent":"\"updux\".UpduxConfig"},{"id":8,"kind":1024,"name":"mappedSelectors","url":"interfaces/_updux_.UpduxConfig.html#mappedSelectors","classes":"tsd-kind-property tsd-parent-kind-interface","parent":"\"updux\".UpduxConfig"},{"id":9,"kind":1024,"name":"effects","url":"interfaces/_updux_.UpduxConfig.html#effects","classes":"tsd-kind-property tsd-parent-kind-interface","parent":"\"updux\".UpduxConfig"},{"id":10,"kind":1024,"name":"reactions","url":"interfaces/_updux_.UpduxConfig.html#reactions","classes":"tsd-kind-property tsd-parent-kind-interface","parent":"\"updux\".UpduxConfig"},{"id":11,"kind":1024,"name":"mappedReaction","url":"interfaces/_updux_.UpduxConfig.html#mappedReaction","classes":"tsd-kind-property tsd-parent-kind-interface","parent":"\"updux\".UpduxConfig"},{"id":12,"kind":128,"name":"Updux","url":"classes/_updux_.Updux.html","classes":"tsd-kind-class tsd-parent-kind-namespace tsd-has-type-parameter","parent":"\"updux\""},{"id":13,"kind":512,"name":"constructor","url":"classes/_updux_.Updux.html#constructor","classes":"tsd-kind-constructor tsd-parent-kind-class tsd-has-type-parameter","parent":"\"updux\".Updux"},{"id":14,"kind":262144,"name":"initial","url":"classes/_updux_.Updux.html#initial","classes":"tsd-kind-get-signature tsd-parent-kind-class","parent":"\"updux\".Updux"},{"id":15,"kind":262144,"name":"selectors","url":"classes/_updux_.Updux.html#selectors","classes":"tsd-kind-get-signature tsd-parent-kind-class","parent":"\"updux\".Updux"}],"index":{"version":"2.3.9","fields":["name","parent"],"fieldVectors":[["name/0",[0,24.277]],["parent/0",[]],["name/1",[1,13.291]],["parent/1",[]],["name/2",[2,24.277]],["parent/2",[1,1.256]],["name/3",[3,19.169]],["parent/3",[4,0.55]],["name/4",[5,24.277]],["parent/4",[4,0.55]],["name/5",[6,24.277]],["parent/5",[4,0.55]],["name/6",[7,19.169]],["parent/6",[4,0.55]],["name/7",[8,24.277]],["parent/7",[4,0.55]],["name/8",[9,24.277]],["parent/8",[4,0.55]],["name/9",[10,24.277]],["parent/9",[4,0.55]],["name/10",[11,24.277]],["parent/10",[4,0.55]],["name/11",[12,24.277]],["parent/11",[4,0.55]],["name/12",[1,13.291]],["parent/12",[1,1.256]],["name/13",[13,24.277]],["parent/13",[14,1.493]],["name/14",[3,19.169]],["parent/14",[14,1.493]],["name/15",[7,19.169]],["parent/15",[14,1.493]]],"invertedIndex":[["actions",{"_index":6,"name":{"5":{}},"parent":{}}],["constructor",{"_index":13,"name":{"13":{}},"parent":{}}],["dict",{"_index":0,"name":{"0":{}},"parent":{}}],["effects",{"_index":10,"name":{"9":{}},"parent":{}}],["initial",{"_index":3,"name":{"3":{},"14":{}},"parent":{}}],["mappedreaction",{"_index":12,"name":{"11":{}},"parent":{}}],["mappedselectors",{"_index":9,"name":{"8":{}},"parent":{}}],["mutations",{"_index":8,"name":{"7":{}},"parent":{}}],["reactions",{"_index":11,"name":{"10":{}},"parent":{}}],["selectors",{"_index":7,"name":{"6":{},"15":{}},"parent":{}}],["subduxes",{"_index":5,"name":{"4":{}},"parent":{}}],["updux",{"_index":1,"name":{"1":{},"12":{}},"parent":{"2":{},"12":{}}}],["updux\".updux",{"_index":14,"name":{},"parent":{"13":{},"14":{},"15":{}}}],["updux\".upduxconfig",{"_index":4,"name":{},"parent":{"3":{},"4":{},"5":{},"6":{},"7":{},"8":{},"9":{},"10":{},"11":{}}}],["upduxconfig",{"_index":2,"name":{"2":{}},"parent":{}}]],"pipeline":[]}} \ No newline at end of file +window.searchData = {"kinds":{"4":"Namespace","128":"Class","256":"Interface","512":"Constructor","1024":"Property","2048":"Method","65536":"Type literal","262144":"Accessor","4194304":"Type alias"},"rows":[{"id":0,"kind":4194304,"name":"Dict","url":"modules.html#Dict","classes":"tsd-kind-type-alias tsd-has-type-parameter"},{"id":1,"kind":4194304,"name":"Mutation","url":"modules.html#Mutation","classes":"tsd-kind-type-alias tsd-has-type-parameter"},{"id":2,"kind":65536,"name":"__type","url":"modules.html#Mutation.__type","classes":"tsd-kind-type-literal tsd-parent-kind-type-alias","parent":"Mutation"},{"id":3,"kind":4194304,"name":"ActionGenerator","url":"modules.html#ActionGenerator","classes":"tsd-kind-type-alias"},{"id":4,"kind":4,"name":"\"updux\"","url":"modules/_updux_.html","classes":"tsd-kind-namespace"},{"id":5,"kind":256,"name":"UpduxConfig","url":"interfaces/_updux_.UpduxConfig.html","classes":"tsd-kind-interface tsd-parent-kind-namespace tsd-has-type-parameter","parent":"\"updux\""},{"id":6,"kind":1024,"name":"initial","url":"interfaces/_updux_.UpduxConfig.html#initial","classes":"tsd-kind-property tsd-parent-kind-interface","parent":"\"updux\".UpduxConfig"},{"id":7,"kind":1024,"name":"subduxes","url":"interfaces/_updux_.UpduxConfig.html#subduxes","classes":"tsd-kind-property tsd-parent-kind-interface","parent":"\"updux\".UpduxConfig"},{"id":8,"kind":1024,"name":"actions","url":"interfaces/_updux_.UpduxConfig.html#actions","classes":"tsd-kind-property tsd-parent-kind-interface","parent":"\"updux\".UpduxConfig"},{"id":9,"kind":1024,"name":"selectors","url":"interfaces/_updux_.UpduxConfig.html#selectors","classes":"tsd-kind-property tsd-parent-kind-interface","parent":"\"updux\".UpduxConfig"},{"id":10,"kind":1024,"name":"mutations","url":"interfaces/_updux_.UpduxConfig.html#mutations","classes":"tsd-kind-property tsd-parent-kind-interface","parent":"\"updux\".UpduxConfig"},{"id":11,"kind":1024,"name":"mappedSelectors","url":"interfaces/_updux_.UpduxConfig.html#mappedSelectors","classes":"tsd-kind-property tsd-parent-kind-interface","parent":"\"updux\".UpduxConfig"},{"id":12,"kind":1024,"name":"effects","url":"interfaces/_updux_.UpduxConfig.html#effects","classes":"tsd-kind-property tsd-parent-kind-interface","parent":"\"updux\".UpduxConfig"},{"id":13,"kind":1024,"name":"reactions","url":"interfaces/_updux_.UpduxConfig.html#reactions","classes":"tsd-kind-property tsd-parent-kind-interface","parent":"\"updux\".UpduxConfig"},{"id":14,"kind":1024,"name":"mappedReaction","url":"interfaces/_updux_.UpduxConfig.html#mappedReaction","classes":"tsd-kind-property tsd-parent-kind-interface","parent":"\"updux\".UpduxConfig"},{"id":15,"kind":128,"name":"Updux","url":"classes/_updux_.Updux.html","classes":"tsd-kind-class tsd-parent-kind-namespace tsd-has-type-parameter","parent":"\"updux\""},{"id":16,"kind":512,"name":"constructor","url":"classes/_updux_.Updux.html#constructor","classes":"tsd-kind-constructor tsd-parent-kind-class tsd-has-type-parameter","parent":"\"updux\".Updux"},{"id":17,"kind":262144,"name":"initial","url":"classes/_updux_.Updux.html#initial","classes":"tsd-kind-get-signature tsd-parent-kind-class","parent":"\"updux\".Updux"},{"id":18,"kind":262144,"name":"selectors","url":"classes/_updux_.Updux.html#selectors","classes":"tsd-kind-get-signature tsd-parent-kind-class","parent":"\"updux\".Updux"},{"id":19,"kind":2048,"name":"setMutation","url":"classes/_updux_.Updux.html#setMutation","classes":"tsd-kind-method tsd-parent-kind-class tsd-has-type-parameter","parent":"\"updux\".Updux"},{"id":20,"kind":2048,"name":"setAction","url":"classes/_updux_.Updux.html#setAction","classes":"tsd-kind-method tsd-parent-kind-class","parent":"\"updux\".Updux"}],"index":{"version":"2.3.9","fields":["name","parent"],"fieldVectors":[["name/0",[0,26.856]],["parent/0",[]],["name/1",[1,21.748]],["parent/1",[]],["name/2",[2,26.856]],["parent/2",[1,1.984]],["name/3",[3,26.856]],["parent/3",[]],["name/4",[4,15.87]],["parent/4",[]],["name/5",[5,26.856]],["parent/5",[4,1.448]],["name/6",[6,21.748]],["parent/6",[7,0.766]],["name/7",[8,26.856]],["parent/7",[7,0.766]],["name/8",[9,26.856]],["parent/8",[7,0.766]],["name/9",[10,21.748]],["parent/9",[7,0.766]],["name/10",[11,26.856]],["parent/10",[7,0.766]],["name/11",[12,26.856]],["parent/11",[7,0.766]],["name/12",[13,26.856]],["parent/12",[7,0.766]],["name/13",[14,26.856]],["parent/13",[7,0.766]],["name/14",[15,26.856]],["parent/14",[7,0.766]],["name/15",[4,15.87]],["parent/15",[4,1.448]],["name/16",[16,26.856]],["parent/16",[17,1.265]],["name/17",[6,21.748]],["parent/17",[17,1.265]],["name/18",[10,21.748]],["parent/18",[17,1.265]],["name/19",[18,26.856]],["parent/19",[17,1.265]],["name/20",[19,26.856]],["parent/20",[17,1.265]]],"invertedIndex":[["__type",{"_index":2,"name":{"2":{}},"parent":{}}],["actiongenerator",{"_index":3,"name":{"3":{}},"parent":{}}],["actions",{"_index":9,"name":{"8":{}},"parent":{}}],["constructor",{"_index":16,"name":{"16":{}},"parent":{}}],["dict",{"_index":0,"name":{"0":{}},"parent":{}}],["effects",{"_index":13,"name":{"12":{}},"parent":{}}],["initial",{"_index":6,"name":{"6":{},"17":{}},"parent":{}}],["mappedreaction",{"_index":15,"name":{"14":{}},"parent":{}}],["mappedselectors",{"_index":12,"name":{"11":{}},"parent":{}}],["mutation",{"_index":1,"name":{"1":{}},"parent":{"2":{}}}],["mutations",{"_index":11,"name":{"10":{}},"parent":{}}],["reactions",{"_index":14,"name":{"13":{}},"parent":{}}],["selectors",{"_index":10,"name":{"9":{},"18":{}},"parent":{}}],["setaction",{"_index":19,"name":{"20":{}},"parent":{}}],["setmutation",{"_index":18,"name":{"19":{}},"parent":{}}],["subduxes",{"_index":8,"name":{"7":{}},"parent":{}}],["updux",{"_index":4,"name":{"4":{},"15":{}},"parent":{"5":{},"15":{}}}],["updux\".updux",{"_index":17,"name":{},"parent":{"16":{},"17":{},"18":{},"19":{},"20":{}}}],["updux\".upduxconfig",{"_index":7,"name":{},"parent":{"6":{},"7":{},"8":{},"9":{},"10":{},"11":{},"12":{},"13":{},"14":{}}}],["upduxconfig",{"_index":5,"name":{"5":{}},"parent":{}}]],"pipeline":[]}} \ No newline at end of file diff --git a/docs/API/classes/_updux_.Updux.html b/docs/API/classes/_updux_.Updux.html index dd48f2b..087d444 100644 --- a/docs/API/classes/_updux_.Updux.html +++ b/docs/API/classes/_updux_.Updux.html @@ -1 +1,11 @@ -Updux
Options
All
  • Public
  • Public/Protected
  • All
Menu

Class Updux<TState>

Type parameters

  • TState = unknown

Hierarchy

  • Updux

Index

Constructors

Accessors

Constructors

constructor

  • Type parameters

    • TState = unknown

    Parameters

    Returns Updux<TState>

Accessors

initial

  • get initial(): TState
  • Returns TState

selectors

  • get selectors(): unknown
  • Returns unknown

Generated using TypeDoc

\ No newline at end of file +Updux
Options
All
  • Public
  • Public/Protected
  • All
Menu

Class Updux<TState>

Type parameters

  • TState = unknown

Hierarchy

  • Updux

Index

Constructors

constructor

  • Type parameters

    • TState = unknown

    Parameters

    Returns Updux<TState>

Accessors

initial

  • get initial(): TState
  • Returns TState

selectors

  • get selectors(): unknown
  • Returns unknown

Methods

setAction

  • setAction(actionType: string, payloadFunc?: Function): any
  • +

    Registers the action for the dux. +If no payload function is provided, whatever is +given as an argument to the action generator will +be set as-is in the action's payload.

    +

    Parameters

    • actionType: string
    • Optional payloadFunc: Function

    Returns any

setMutation

  • setMutation<TMutation>(actionType: string, mutation: TMutation): TMutation
  • setMutation<TMutation>(action: ActionGenerator, mutation: TMutation): TMutation
  • +

    Sets the local mutation for the given action.

    +

    The action can be specified via its type +or its generator.

    +

    Returns the same mutation function.

    +

    Type parameters

    Parameters

    • actionType: string
    • mutation: TMutation

    Returns TMutation

  • Type parameters

    Parameters

    Returns TMutation

Generated using TypeDoc

\ No newline at end of file diff --git a/docs/API/index.html b/docs/API/index.html index be83de2..cbaa393 100644 --- a/docs/API/index.html +++ b/docs/API/index.html @@ -89,4 +89,4 @@ well with Immer. can be used to wrap all mutations with it:

import Updux from 'updux';
import { produce } from 'Immer';

const updux = new Updux({
initial: { counter: 0 },
groomMutations: mutation => (...args) => produce( mutation(...args) ),
mutations: {
add: (inc=1) => draft => draft.counter += inc
}
});
-

Generated using TypeDoc

\ No newline at end of file +

Generated using TypeDoc

\ No newline at end of file diff --git a/docs/API/modules.html b/docs/API/modules.html index 9ac765d..031e49b 100644 --- a/docs/API/modules.html +++ b/docs/API/modules.html @@ -1 +1 @@ -Updux
Options
All
  • Public
  • Public/Protected
  • All
Menu

Updux

Index

Namespaces

Type aliases

Type aliases

Dict

Dict<T>: Record<string, T>

Type parameters

  • T

Generated using TypeDoc

\ No newline at end of file +Updux
Options
All
  • Public
  • Public/Protected
  • All
Menu

Updux

Index

Type aliases

ActionGenerator

ActionGenerator: { type: string } & ((...args: any[]) => { payload?: unknown; type: string })

Dict

Dict<T>: Record<string, T>

Type parameters

  • T

Mutation

Mutation<TState>: (payload: unknown, action: Record<string, unknown>) => (state: TState) => TState

Type parameters

  • TState = unknown

Type declaration

    • (payload: unknown, action: Record<string, unknown>): (state: TState) => TState
    • Parameters

      • payload: unknown
      • action: Record<string, unknown>

      Returns (state: TState) => TState

        • (state: TState): TState
        • Parameters

          • state: TState

          Returns TState

Generated using TypeDoc

\ No newline at end of file diff --git a/docs/README.md b/docs/README.md index 70b84e5..d034c88 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,23 +1,21 @@ - -# What's Updux? +## What's Updux? So, I'm a fan of [Redux](https://redux.js.org). As I was looking into tools to help cut on its boilerplate, I came across [rematch](https://rematch.github.io/rematch). It has some pretty darn good ideas. -Keeping mutations and asynchronous effects close to the -reducer definition? Nice. Automatically infering the -actions from the said mutations and effects? Genius! - But it also enforces a flat hierarchy of reducers -- where -is the fun in that? And I'm also having a strong love for -[Updeep](https://github.com/substantial/updeep), so I want reducer state updates to leverage the heck out of it. +is the fun in that? + +I'm also having a strong love for +[Updeep](https://github.com/substantial/updeep), so I wanted a framework where +I could use it to define reducer state updates. Hence: `Updux`. Heavily inspired by `rematch`, but twisted to work with `updeep` and to fit my peculiar needs. It offers features such as -* Mimic the way VueX has mutations (reducer reactions to specific actions) and +* Mimic the way VueX has mutations (per-action reducer logic) and effects (middleware reacting to actions that can be asynchronous and/or have side-effects), so all things pertaining to a store are defined in the space place. @@ -26,9 +24,7 @@ to work with `updeep` and to fit my peculiar needs. It offers features such as store. * Mutations have a signature that is friendly to Updux and Immer. * Mutations auto-unwrapping the payload of actions for you. -* TypeScript types. -* Leverage [ts-action](https://www.npmjs.com/package/ts-action) for action - creation. +* TypeScript support. **Fair warning**: this package is still very new, likely to go through big changes before I find the perfect balance between ease of use and sanity. @@ -36,70 +32,36 @@ Caveat Emptor. # Synopsis -``` -import Updux from 'updux'; -import { action, payload } from 'ts-action'; +```js +import { Updux } from 'updux'; +import u from 'updeep'; +import add from 'lodash/fp/add.js'; import otherDux from './otherUpdux'; -const inc = action( 'INC', payload() ); - -const updux = new Updux({ +const dux = new Updux({ initial: { counter: 0, }, actions: { - inc + inc: null }, subduxes: { otherDux, } }); -updux.addMutation( inc, increment => u({counter: s => s + increment })); +dux.setMutation('inc', (increment) => u({ counter: add(increment) })); -updux.addEffect( '*', api => next => action => { +dux.addEffect( '*', api => next => action => { console.log( "hey, look, an action zoomed by!", action ); next(action); } ); -const myDux = updux.asDux; +const store = dux.createStore(); -const store = myDux.createStore(); +store.dispatch.inc(1); -store.dispatch( myDux.actions.inc(3) ); +console.log( store.getState().counter ); // prints 1 ``` -# Description - -The formal documentation of the class Updux and its associated functions and -types can be found over [here](https://yanick.github.io/updux/docs/classes/updux.html). - -## Exporting upduxes - -If you are creating upduxes that will be used as subduxes -by other upduxes, or as -[ducks](https://github.com/erikras/ducks-modular-redux)-like containers, I -recommend that you export the "compiled" (as in, no more editable and with all its properties resolved) output of the Updux instance via its `asDux()` getter: - -``` -import Updux from 'updux'; - -const updux = new Updux({ ... }); - -export default updux.asDux; -``` - -Then you can use them as subduxes like this: - -``` -import Updux from 'updux'; -import foo from './foo'; // foo is a dux -import bar from './bar'; // bar is a dux as well - -const updux = new Updux({ - subduxes: { - foo, bar - } -}); -``` diff --git a/docs/_sidebar.md b/docs/_sidebar.md index d741133..5697e6f 100644 --- a/docs/_sidebar.md +++ b/docs/_sidebar.md @@ -1,4 +1,4 @@ - - [README](/README.md) + - [Intro](/README.md) - [Tutorial](/tutorial.md) - [Concepts](/concepts.md) - [Recipes](/recipes.md) diff --git a/docs/tutorial.md b/docs/tutorial.md index 512fdc3..6671f3d 100644 --- a/docs/tutorial.md +++ b/docs/tutorial.md @@ -3,72 +3,45 @@ This tutorial walks you through the features of `Updux` using the time-honored example of the implementation of Todo list store. -This tutorial assumes that our project is written in TypeScript, and -that we are using [updeep](https://www.npmjs.com/package/updeep) to -help with immutability and deep merging and [ts-action][] to manage our -actions. This is the recommended setup, but -neither of those two architecture -decisions are mandatory; Updux is equally usable in a pure-JavaScript setting, -and `updeep` can easily be substitued with, say, [immer][], [lodash][], or even -just plain JavaScript. Eventually, I plan to write a version of this tutorial -with all those different configurations. - -Also, the code used here is also available in the project repository, in the -`src/tutorial` directory. +We'll be using +[updeep](https://www.npmjs.com/package/updeep) to +help with immutability and deep merging, +but that's totally optional. If `updeep` is not your bag, +it can easily be substitued with, say, [immer][], [lodash][], or even +plain JavaScript. ## Definition of the state -First thing first: let's define the type of our store: +To begin with, let's define that has nothing but an initial state. -``` -type Todo = { - id: number; - description: string; - done: boolean; -}; +```js +import { Updux } from 'updux'; -type TodoStore = { - next_id: number; - todos: Todo[]; -}; -``` - -With that, let's create our very first Updux: - -``` -import Updux from 'updux'; - -const todosUpdux = new Updux({ +const todosDux = new Updux({ initial: { next_id: 1, todos: [], - } as TodoStore + } }); ``` -Note that we explicitly cast the initial state as `as TodoStore`. This lets -Updux know what is the store's state. - -This being said, congrats! You have written your first Updux object. It +Congrats! You have written your first Updux object. It doesn't do a lot, but you can already create a store out of it, and its initial state will be automatically set: -``` -const store = todosUpdux.createStore(); +```js +const store = todosDux.createStore(); -console.log(store.getState()); -// { next_id: 1, todos: [] } +console.log(store.getState()); // prints { next_id: 1, todos: [] } ``` ## Add actions This is all good, but a little static. Let's add actions! -``` -import { action, payload } from 'ts-action'; - -const add_todo = action('add_todo', payload() ); -const todo_done = action('todo_done', payload() ); +```js +todosDux.setAction( 'addTodo' ); +todosDux.setAction( 'todoDone' ); ``` Now, there is a lot of ways to add actions to a Updux object. diff --git a/src/Updux.js b/src/Updux.js index c8001aa..007c3e7 100644 --- a/src/Updux.js +++ b/src/Updux.js @@ -128,7 +128,7 @@ export class Updux { this.#subscriptions = [...this.#subscriptions, subscription]; } - addAction(type, payloadFunc) { + setAction(type, payloadFunc) { const theAction = action(type, payloadFunc); this.#actions = { ...this.#actions, [type]: theAction }; @@ -144,7 +144,7 @@ export class Updux { return func; } - addMutation(name, mutation) { + setMutation(name, mutation) { if (typeof name === 'function') name = name.type; this.#mutations = { @@ -152,7 +152,7 @@ export class Updux { [name]: mutation, }; - return this; + return mutation; } addEffect(action, effect) { @@ -304,6 +304,3 @@ export class Updux { return store; } } - -const x = new Updux(); -x.selectors; diff --git a/src/Updux.test.js b/src/Updux.test.js index c8e1126..2f66b33 100644 --- a/src/Updux.test.js +++ b/src/Updux.test.js @@ -45,13 +45,13 @@ test('basic actions', async (t) => { t.same(Object.keys(dux.actions).sort(), ['bar', 'foo']); }); -test('addAction', async (t) => { +test('setAction', async (t) => { const dux = new Updux({ actions: { bar: action('bar'), }, }); - dux.addAction('foo'); + dux.setAction('foo'); t.same(Object.keys(dux.actions).sort(), ['bar', 'foo']); }); @@ -81,7 +81,7 @@ test('basic selectors', async (t) => { (add) => add + foo ); - dux.addAction('stuff'); + dux.setAction('stuff'); t.equal(dux.selectors.getBar({ bar: 3 }), 3); t.equal(dux.selectors.getFoo({ foo: 3 }), 3); @@ -100,8 +100,8 @@ test('mutations', async (t) => { const alpha = new Updux({ initial: { quux: 3 }, }); - alpha.addAction('add'); - alpha.addMutation('add', (toAdd) => (state) => ({ + alpha.setAction('add'); + alpha.setMutation('add', (toAdd) => (state) => ({ quux: state.quux + toAdd, })); @@ -112,12 +112,12 @@ test('mutations', async (t) => { }, subduxes: { alpha }, }); - dux.addAction('subtract'); - dux.addMutation('add', (toAdd) => (state) => ({ + dux.setAction('subtract'); + dux.setMutation('add', (toAdd) => (state) => ({ ...state, foo: state.foo + toAdd, })); - dux.addMutation('subtract', (toSubtract) => (state) => ({ + dux.setMutation('subtract', (toSubtract) => (state) => ({ ...state, bar: state.bar - toSubtract, })); diff --git a/src/documentation.test.js b/src/documentation.test.js new file mode 100644 index 0000000..e6bf6c2 --- /dev/null +++ b/src/documentation.test.js @@ -0,0 +1,48 @@ +import { test } from 'tap'; +import u from 'updeep'; +import add from 'lodash/fp/add.js'; + +import { Updux } from './index.js'; + +test('README.md', async (t) => { + const otherDux = new Updux({}); + + const dux = new Updux({ + initial: { + counter: 0, + }, + actions: { + inc: null, + }, + subduxes: { + otherDux, + }, + }); + + dux.setMutation('inc', (increment) => u({ counter: add(increment) })); + + dux.addEffect('*', (api) => (next) => (action) => { + next(action); + }); + + const store = dux.createStore(); + + store.dispatch.inc(1); + + t.equal(store.getState().counter, 1); +}); + + +test('tutorial', async (t) => { + + const todosDux = new Updux({ + initial: { + next_id: 1, + todos: [], + } + }); + + todosDux.setAction( 'addTodo' ); + todosDux.setAction( 'todoDone' ); + +}) diff --git a/src/index.js b/src/index.js index 0a0fa5f..fb808a9 100644 --- a/src/index.js +++ b/src/index.js @@ -1,16 +1,2 @@ -import Updux from './Updux.js'; +export { Updux } from './Updux.js'; -export { - /** - * The {@link Updux} class - */ - Updux -}; - -/** - * `Updux` is a way to minimize and simplify the boilerplate associated with the - * creation of a `Redux` store. It takes a shorthand configuration - * object, and generates the appropriate reducer, actions, middleware, etc. - * In true `Redux`-like fashion, upduxes can be made of sub-upduxes (`subduxes` for short) for different slices of the root state. - * @module updux - */ diff --git a/src/mutations.test.js b/src/mutations.test.js index 5a31c31..5979409 100644 --- a/src/mutations.test.js +++ b/src/mutations.test.js @@ -81,7 +81,7 @@ test('order of processing', async (t) => { t.same(dux.reducer(undefined, foo()), { x: ['subdux', 'main'] }); }); -test('addMutation', async (t) => { +test('setMutation', async (t) => { const foo = action('foo'); const dux = new Updux({ @@ -90,13 +90,13 @@ test('addMutation', async (t) => { t.equal(dux.reducer(undefined, foo()), '', 'noop'); - dux.addMutation('foo', () => () => 'foo'); + dux.setMutation('foo', () => () => 'foo'); t.equal(dux.reducer(undefined, foo()), 'foo', 'foo was added'); await t.test('name as function', async (t) => { const bar = action('bar'); - dux.addMutation(bar, () => () => 'bar'); + dux.setMutation(bar, () => () => 'bar'); t.equal(dux.reducer(undefined, bar()), 'bar', 'bar was added'); }); diff --git a/types/index.d.ts b/types/index.d.ts index 9acd963..f271176 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -1,5 +1,15 @@ type Dict = Record; +type Mutation = ( + payload: unknown, + action: Record +) => (state: TState) => TState; + +type ActionGenerator = { type: string } & ((...args: any[]) => { + type: string; + payload?: unknown; +}); + declare module 'updux' { /** * Configuration object typically passed to the constructor of the class Updux. @@ -14,7 +24,7 @@ declare module 'updux' { /** * Subduxes to be merged to this dux. */ - subduxes?: Dict; + subduxes?: Dict; /** * Local actions. @@ -59,5 +69,30 @@ declare module 'updux' { get initial(): TState; get selectors(): unknown; + + /** + * Sets the local mutation for the given action. + * + * The action can be specified via its type + * or its generator. + * + * Returns the same mutation function. + */ + setMutation( + actionType: string, + mutation: TMutation + ): TMutation; + setMutation( + action: ActionGenerator, + mutation: TMutation + ): TMutation; + + /** + * Registers the action for the dux. + * If no payload function is provided, whatever is + * given as an argument to the action generator will + * be set as-is in the action's payload. + */ + setAction(actionType: string, payloadFunc?: Function); } }