rename leftover from * to +

This commit is contained in:
Yanick Champoux 2021-10-13 13:54:17 -04:00
parent 9778e04a8d
commit 6dd8b1af9e
10 changed files with 93 additions and 134 deletions

File diff suppressed because one or more lines are too long

View File

@ -1 +1,3 @@
<!DOCTYPE html><html class="default no-js"><head><meta charSet="utf-8"/><meta http-equiv="X-UA-Compatible" content="IE=edge"/><title>&quot;updux&quot; | Updux</title><meta name="description" content="Documentation for Updux"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="../assets/style.css"/><link rel="stylesheet" href="../assets/highlight.css"/><script async src="../assets/search.js" id="search-script"></script></head><body><header><div class="tsd-page-toolbar"><div class="container"><div class="table-wrap"><div class="table-cell" id="tsd-search" data-base=".."><div class="field"><label for="tsd-search-field" class="tsd-widget search no-caption">Search</label><input type="text" id="tsd-search-field"/></div><ul class="results"><li class="state loading">Preparing search index...</li><li class="state failure">The search index is not available</li></ul><a href="../index.html" class="title">Updux</a></div><div class="table-cell" id="tsd-widgets"><div id="tsd-filter"><a href="#" class="tsd-widget options no-caption" data-toggle="options">Options</a><div class="tsd-filter-group"><div class="tsd-select" id="tsd-filter-visibility"><span class="tsd-select-label">All</span><ul class="tsd-select-list"><li data-value="public">Public</li><li data-value="protected">Public/Protected</li><li data-value="private" class="selected">All</li></ul></div> <input type="checkbox" id="tsd-filter-inherited" checked/><label class="tsd-widget" for="tsd-filter-inherited">Inherited</label></div></div><a href="#" class="tsd-widget menu no-caption" data-toggle="menu">Menu</a></div></div></div></div><div class="tsd-page-title"><div class="container"><ul class="tsd-breadcrumb"><li><a href="../modules.html">Updux</a></li><li><a href="_updux_.html">&quot;updux&quot;</a></li></ul><h1>Namespace &quot;updux&quot;</h1></div></div></header><div class="container container-main"><div class="row"><div class="col-8 col-content"><section class="tsd-panel-group tsd-index-group"><h2>Index</h2><section class="tsd-panel tsd-index-panel"><div class="tsd-index-content"><section class="tsd-index-section "><h3>Classes</h3><ul class="tsd-index-list"><li class="tsd-kind-class tsd-parent-kind-namespace tsd-has-type-parameter"><a href="../classes/_updux_.Updux.html" class="tsd-kind-icon">Updux</a></li></ul></section><section class="tsd-index-section "><h3>Interfaces</h3><ul class="tsd-index-list"><li class="tsd-kind-interface tsd-parent-kind-namespace tsd-has-type-parameter"><a href="../interfaces/_updux_.UpduxConfig.html" class="tsd-kind-icon">Updux<wbr/>Config</a></li></ul></section></div></section></section></div><div class="col-4 col-menu menu-sticky-wrap menu-highlight"><nav class="tsd-navigation primary"><ul><li class=""><a href="../modules.html">Exports</a></li><li class="current tsd-kind-namespace"><a href="_updux_.html">&quot;updux&quot;</a></li></ul></nav><nav class="tsd-navigation secondary menu-sticky"><ul><li class="tsd-kind-class tsd-parent-kind-namespace tsd-has-type-parameter"><a href="../classes/_updux_.Updux.html" class="tsd-kind-icon">Updux</a></li><li class="tsd-kind-interface tsd-parent-kind-namespace tsd-has-type-parameter"><a href="../interfaces/_updux_.UpduxConfig.html" class="tsd-kind-icon">Updux<wbr/>Config</a></li></ul></nav></div></div></div><footer class="with-border-bottom"><div class="container"><h2>Settings</h2><p>Theme <select id="theme"><option value="os">OS</option><option value="light">Light</option><option value="dark">Dark</option></select></p></div></footer><div class="container tsd-generator"><p>Generated using <a href="https://typedoc.org/" target="_blank">TypeDoc</a></p></div><div class="overlay"></div><script src="../assets/main.js"></script></body></html>
<!DOCTYPE html><html class="default no-js"><head><meta charSet="utf-8"/><meta http-equiv="X-UA-Compatible" content="IE=edge"/><title>&quot;updux&quot; | Updux</title><meta name="description" content="Documentation for Updux"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="../assets/style.css"/><link rel="stylesheet" href="../assets/highlight.css"/><script async src="../assets/search.js" id="search-script"></script></head><body><header><div class="tsd-page-toolbar"><div class="container"><div class="table-wrap"><div class="table-cell" id="tsd-search" data-base=".."><div class="field"><label for="tsd-search-field" class="tsd-widget search no-caption">Search</label><input type="text" id="tsd-search-field"/></div><ul class="results"><li class="state loading">Preparing search index...</li><li class="state failure">The search index is not available</li></ul><a href="../index.html" class="title">Updux</a></div><div class="table-cell" id="tsd-widgets"><div id="tsd-filter"><a href="#" class="tsd-widget options no-caption" data-toggle="options">Options</a><div class="tsd-filter-group"><div class="tsd-select" id="tsd-filter-visibility"><span class="tsd-select-label">All</span><ul class="tsd-select-list"><li data-value="public">Public</li><li data-value="protected">Public/Protected</li><li data-value="private" class="selected">All</li></ul></div> <input type="checkbox" id="tsd-filter-inherited" checked/><label class="tsd-widget" for="tsd-filter-inherited">Inherited</label></div></div><a href="#" class="tsd-widget menu no-caption" data-toggle="menu">Menu</a></div></div></div></div><div class="tsd-page-title"><div class="container"><ul class="tsd-breadcrumb"><li><a href="../modules.html">Updux</a></li><li><a href="_updux_.html">&quot;updux&quot;</a></li></ul><h1>Namespace &quot;updux&quot;</h1></div></div></header><div class="container container-main"><div class="row"><div class="col-8 col-content"><section class="tsd-panel-group tsd-index-group"><h2>Index</h2><section class="tsd-panel tsd-index-panel"><div class="tsd-index-content"><section class="tsd-index-section "><h3>Classes</h3><ul class="tsd-index-list"><li class="tsd-kind-class tsd-parent-kind-namespace tsd-has-type-parameter"><a href="../classes/_updux_.Updux.html" class="tsd-kind-icon">Updux</a></li></ul></section><section class="tsd-index-section "><h3>Interfaces</h3><ul class="tsd-index-list"><li class="tsd-kind-interface tsd-parent-kind-namespace tsd-has-type-parameter"><a href="../interfaces/_updux_.UpduxConfig.html" class="tsd-kind-icon">Updux<wbr/>Config</a></li></ul></section><section class="tsd-index-section "><h3>Functions</h3><ul class="tsd-index-list"><li class="tsd-kind-function tsd-parent-kind-namespace"><a href="_updux_.html#action" class="tsd-kind-icon">action</a></li></ul></section></div></section></section><section class="tsd-panel-group tsd-member-group "><h2>Functions</h2><section class="tsd-panel tsd-member tsd-kind-function tsd-parent-kind-namespace"><a name="action" class="tsd-anchor"></a><h3>action</h3><ul class="tsd-signatures tsd-kind-function tsd-parent-kind-namespace"><li class="tsd-signature tsd-kind-icon">action<span class="tsd-signature-symbol">(</span>type<span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">string</span>, payloadFunction<span class="tsd-signature-symbol">?: </span><span class="tsd-signature-type">Function</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol">: </span><a href="../modules.html#ActionGenerator" class="tsd-signature-type" data-tsd-kind="Type alias">ActionGenerator</a></li></ul><ul class="tsd-descriptions"><li class="tsd-description"><aside class="tsd-sources"></aside><div class="tsd-comment tsd-typography"><div class="lead">
<p>Creates an action generator.</p>
</div></div><h4 class="tsd-parameters-title">Parameters</h4><ul class="tsd-parameters"><li><h5>type: <span class="tsd-signature-type">string</span></h5></li><li><h5><span class="tsd-flag ts-flagOptional">Optional</span> payloadFunction: <span class="tsd-signature-type">Function</span></h5></li></ul><h4 class="tsd-returns-title">Returns <a href="../modules.html#ActionGenerator" class="tsd-signature-type" data-tsd-kind="Type alias">ActionGenerator</a></h4></li></ul></section></section></div><div class="col-4 col-menu menu-sticky-wrap menu-highlight"><nav class="tsd-navigation primary"><ul><li class=""><a href="../modules.html">Exports</a></li><li class="current tsd-kind-namespace"><a href="_updux_.html">&quot;updux&quot;</a></li></ul></nav><nav class="tsd-navigation secondary menu-sticky"><ul><li class="tsd-kind-class tsd-parent-kind-namespace tsd-has-type-parameter"><a href="../classes/_updux_.Updux.html" class="tsd-kind-icon">Updux</a></li><li class="tsd-kind-interface tsd-parent-kind-namespace tsd-has-type-parameter"><a href="../interfaces/_updux_.UpduxConfig.html" class="tsd-kind-icon">Updux<wbr/>Config</a></li><li class="tsd-kind-function tsd-parent-kind-namespace"><a href="_updux_.html#action" class="tsd-kind-icon">action</a></li></ul></nav></div></div></div><footer class="with-border-bottom"><div class="container"><h2>Settings</h2><p>Theme <select id="theme"><option value="os">OS</option><option value="light">Light</option><option value="dark">Dark</option></select></p></div></footer><div class="container tsd-generator"><p>Generated using <a href="https://typedoc.org/" target="_blank">TypeDoc</a></p></div><div class="overlay"></div><script src="../assets/main.js"></script></body></html>

View File

@ -1,12 +1,32 @@
# Updux concepts
## actions
## Actions and action generators
Updux internally uses the package `ts-action` to create action creator
functions. Even if you don't use Typescript, I recommend that you use it,
as it does what it does very well. But if you don't want to, no big deal.
Updux will recognize a function as an action creator if it has a `type`
property. So a homegrown creator could be as simple as:
Updux assumes actions following the format
```js
{
type: 'theTypeName',
payload: {
...
}
}
```
The important part is having action parameters in the `payload` property. The
actions can also have other properties, like `meta`. They are mostly ignored
by Updux.
Updux provides an action generator, but you can roll your own if you do wish.
All it needs to do to be recognized as an action generator by Updux is
1. To be a function returning an action (a plain object with at least a
`type` property).
2. The function also needs to have a `type` property itself.
For example, the following function would work:
```js
function action(type) {
@ -14,7 +34,36 @@ function action(type) {
}
```
## effects
### Mutations
The transformations typically
done by a Redux's reducer are called 'mutations' in Updux. A mutation is a
function with the following signature:
```
( payload, action ) => state => {
// ... stuff done here
return new_state;
}
```
The inversion and chaining of parameters from the usual Redux reducer's
signature is there to work with updeep's curried nature. The expansion of
the usual `action` into `(payload, action)` is present because in most cases
`payload` is what we're interested in. So why not make it easily available?
### Leftover mutation
A mutation associated to the special action `+` will match any action that haven't been
explicitly dealt with with any other defined mutation.
```
todosUpdux.addMutation( '+', (payload,action) => state => {
console.log("hey, action has no mutation! ", action.type);
});
```
## Effects
Updux effects are redux middlewares. I kept that format, and the
use of `next` mostly because I wanted to give myself a way to alter

View File

@ -44,142 +44,40 @@ todosDux.setAction( 'addTodo' );
todosDux.setAction( 'todoDone' );
```
Now, there is a lot of ways to add actions to a Updux object.
It can be defined when the object is created:
```
const todosUpdux = new Updux({
actions: {
add_todo,
todo_done,
}
});
```
It can be done via the method `addAction`:
```
todosUpdux.addAction(add_todo);
```
Or it can be directly used in the definition of a mutation or effect, and will
be automatically added to the Updux.
```
todosUpdux.addMutation( add_todo, todoMutation );
```
For TypeScript projects I recommend declaring the actions as part of the
configuration passed to the constructors, as it makes them accessible to the class
at compile-time, and allows Updux to auto-add them to its aggregated `actions` type.
```
const todosUpdux = new Updux({
actions: {
add_todo,
}
});
todosUpdux.addAction(todo_done);
// only `add_todo` is visible to the type
type MyActions = typeof todosUpdux.actions;
// { add_todo: Function }
// but both actions are accessible at runtime
const myAction = ( todosUpdux.actions as any).todo_done(1);
```
### Accessing actions
Once an action is defined, its creator is accessible via the `actions` accessor.
```js
console.log( todosDux.actions.addTodo('write tutorial') ); // prints { type: 'addTodo', payload: 'write tutorial' }
```
console.log( todosUpdux.actions.add_todo('write tutorial') );
// { type: 'add_todo', payload: 'write tutorial' }
```
### What is an action?
In this tutorial we use `ts-action` for all the work, but under the hood Updux defines actions via
their creators, which are expected to be:
1. Functions,
2. returning a plain object of the format `{ type: string; payload?: unknown }`.
3. with an additional property `type`, which is also the action type.
For example, this is a perfectly cromulent action:
```
const add_todo = description => ({ type: 'add_todo', payload: description});
add_todo.type = 'add_todo';
```
## Mutations
Actions that don't do anything are not fun. The transformations typically
done by a Redux's reducer are called 'mutations' in Updux. A mutation is a
function with the following signature:
```
( payload, action ) => state => {
// ... stuff done here
return new_state;
}
```
The inversion and chaining of parameters from the usual Redux reducer's
signature is there to work with `updeep`'s curried nature. The expansion of
the usual `action` into `(payload, action)` is present because in most cases
`payload` is what we're interested in. So why not make it easily available?
### Adding a mutation
As for the actions, a mutation can be defined as part of the Updux
Like actions, a mutation can be defined as part of the Updux
init arguments:
```
const add_todo_mutation = description => ({next_id: id, todos}) => {
return {
next_id: 1 + id,
todos: [...todos, { description, id, done: false }]
}
};
const todosUpdux = new Updux({
actions: { add_todo },
mutations: [
[ add_todo, add_todo_mutation ]
]
});
```
or via the method `addMutation`:
```
todos.addMutation( add_todo, description => ({next_id: id, todos}) => {
return {
next_id: 1 + id,
todos: [...todos, { description, id, done: false }]
```js
const todosDux = new Updux({
actions: {
addTodo: null
},
mutations: {
addTodo: description => ({next_id: id, todos}) => ({
next_id: 1 + id,
todos: [...todos, { description, id, done: false }]
})
}
});
```
This time around, if the project is using TypeScript then the addition of
mutations via `addMutation` is encouraged, as the method signature
has visibility of the types of the action and state.
or via the method `setMutation`:
### Leftover mutation
A mutation with the special action `*` will match any action that haven't been
explicitly dealt with with any other defined mutation.
```
todosUpdux.addMutation( '*', (payload,action) => state => {
console.log("hey, action has no mutation! ", action.type);
});
```js
todosDux.setMutation( 'addTodo', description => ({next_id: id, todos}) => ({
next_id: 1 + id,
todos: [...todos, { description, id, done: false }]
}));
```
## Effects

View File

@ -54,7 +54,7 @@ export class Updux {
this.#mutations = config.mutations ?? {};
Object.keys(this.#mutations)
.filter((action) => action !== '*')
.filter((action) => action !== '+')
.filter((action) => !this.actions.hasOwnProperty(action))
.forEach((action) => {
throw new Error(`action '${action}' is not defined`);

View File

@ -26,7 +26,7 @@ export function buildUpreducer(initial, mutations, subduxes = {}) {
}
}
const a = mutations[action.type] || mutations['*'];
const a = mutations[action.type] || mutations['+'];
if (!a) return newState;

View File

@ -45,4 +45,6 @@ test('tutorial', async (t) => {
todosDux.setAction( 'addTodo' );
todosDux.setAction( 'todoDone' );
t.same( todosDux.actions.addTodo('write tutorial') , { type: 'addTodo', payload: 'write tutorial' });
})

View File

@ -1,2 +1,2 @@
export { Updux } from './Updux.js';
export { action } from './actions.js';

View File

@ -27,7 +27,7 @@ test('override', async (t) => {
const dux = new Updux({
initial: { alpha: [] },
mutations: {
'*': (payload, action) => (state) => ({
'+': (payload, action) => (state) => ({
...state,
alpha: [...state.alpha, action.type],
}),

8
types/index.d.ts vendored
View File

@ -95,4 +95,12 @@ declare module 'updux' {
*/
setAction(actionType: string, payloadFunc?: Function);
}
/**
* Creates an action generator.
*/
export function action(
actionType: string,
payloadFunction?: Function
): ActionGenerator;
}