corvid-storeon
Advanced tools
Comparing version
@@ -70,24 +70,22 @@ /** | ||
var createStore$1 = function (modules) { | ||
var store = storeon(modules); | ||
var page = []; | ||
var subs = []; | ||
const createStore$1 = (modules) => { | ||
const store = storeon(modules); | ||
const page = []; | ||
let subs = []; | ||
store.on('@changed', function (state, data) { | ||
subs.forEach(function (s) { | ||
var changesInKeys = s.keys.some(function (key) { | ||
return key in data; | ||
$w.onReady(() => { | ||
store.dispatch('@ready'); | ||
store.on('@changed', (state, data) => { | ||
subs.forEach((s) => { | ||
const changesInKeys = s.keys.some((key) => key in data); | ||
if (changesInKeys) { | ||
s.cb(state); | ||
} | ||
}); | ||
if (changesInKeys) { | ||
s.cb(state); | ||
} | ||
}); | ||
}); | ||
$w.onReady(function () { | ||
var state = store.get(); | ||
page.concat(subs).forEach(function (s) { | ||
s.cb(state); | ||
page.concat(subs).forEach((s) => { | ||
s.cb(store.get()); | ||
}); | ||
@@ -100,20 +98,18 @@ }); | ||
connect: function () { | ||
var l = arguments.length - 1; | ||
var cb = arguments[l]; | ||
connect() { | ||
const l = arguments.length - 1; | ||
const cb = arguments[l]; | ||
subs.push({ | ||
keys: [].slice.call(arguments, 0, l), | ||
cb: cb | ||
cb | ||
}); | ||
return function () { | ||
subs = subs.filter(function (s) { | ||
return s.cb !== cb; | ||
}); | ||
return () => { | ||
subs = subs.filter((s) => s.cb !== cb); | ||
}; | ||
}, | ||
connectPage: function (cb) { | ||
page.push({ cb: cb }); | ||
connectPage(cb) { | ||
page.push({ cb }); | ||
} | ||
@@ -120,0 +116,0 @@ }; |
@@ -74,24 +74,22 @@ 'use strict'; | ||
var createStore$1 = function (modules) { | ||
var store = storeon(modules); | ||
var page = []; | ||
var subs = []; | ||
const createStore$1 = (modules) => { | ||
const store = storeon(modules); | ||
const page = []; | ||
let subs = []; | ||
store.on('@changed', function (state, data) { | ||
subs.forEach(function (s) { | ||
var changesInKeys = s.keys.some(function (key) { | ||
return key in data; | ||
$w.onReady(() => { | ||
store.dispatch('@ready'); | ||
store.on('@changed', (state, data) => { | ||
subs.forEach((s) => { | ||
const changesInKeys = s.keys.some((key) => key in data); | ||
if (changesInKeys) { | ||
s.cb(state); | ||
} | ||
}); | ||
if (changesInKeys) { | ||
s.cb(state); | ||
} | ||
}); | ||
}); | ||
$w.onReady(function () { | ||
var state = store.get(); | ||
page.concat(subs).forEach(function (s) { | ||
s.cb(state); | ||
page.concat(subs).forEach((s) => { | ||
s.cb(store.get()); | ||
}); | ||
@@ -104,20 +102,18 @@ }); | ||
connect: function () { | ||
var l = arguments.length - 1; | ||
var cb = arguments[l]; | ||
connect() { | ||
const l = arguments.length - 1; | ||
const cb = arguments[l]; | ||
subs.push({ | ||
keys: [].slice.call(arguments, 0, l), | ||
cb: cb | ||
cb | ||
}); | ||
return function () { | ||
subs = subs.filter(function (s) { | ||
return s.cb !== cb; | ||
}); | ||
return () => { | ||
subs = subs.filter((s) => s.cb !== cb); | ||
}; | ||
}, | ||
connectPage: function (cb) { | ||
page.push({ cb: cb }); | ||
connectPage(cb) { | ||
page.push({ cb }); | ||
} | ||
@@ -124,0 +120,0 @@ }; |
{ | ||
"name": "corvid-storeon", | ||
"version": "1.2.0", | ||
"version": "2.0.0", | ||
"description": "A tiny event-based state manager Storeon for Corvid by Wix", | ||
@@ -8,4 +8,4 @@ "main": "dist/index.js", | ||
"scripts": { | ||
"lint": "eslint src/** tests/** --fix", | ||
"lint-ci": "eslint src/** dist/** tests/**", | ||
"lint-js": "eslint src/** dist/** tests/**", | ||
"lint-md": "markdownlint '**/*.md' --ignore node_modules", | ||
"dist": "rollup --config rollup.config.js && eslint dist/** --fix", | ||
@@ -16,4 +16,7 @@ "test": "jest tests/**.test.js" | ||
"eslint": "^6.8.0", | ||
"jest": "^24.9.0", | ||
"rollup": "^1.29.0", | ||
"husky": "^4.2.3", | ||
"jest": "^25.1.0", | ||
"markdownlint": "^0.19.0", | ||
"markdownlint-cli": "^0.22.0", | ||
"rollup": "^1.32.0", | ||
"rollup-plugin-commonjs": "^10.1.0", | ||
@@ -23,2 +26,7 @@ "rollup-plugin-node-resolve": "^5.2.0", | ||
}, | ||
"husky": { | ||
"hooks": { | ||
"pre-commit": "npm run dist && npm run lint-js && npm run lint-md && npm test" | ||
} | ||
}, | ||
"repository": { | ||
@@ -25,0 +33,0 @@ "type": "git", |
208
README.md
# corvid-storeon | ||
[](https://github.com/shoonia/corvid-storeon/actions) | ||
@@ -9,12 +10,16 @@ [](https://www.npmjs.com/package/corvid-storeon) | ||
A tiny event-based state manager [Storeon](https://github.com/storeon/storeon) for [Corvid](https://www.wix.com/corvid) by Wix. | ||
A tiny event-based state manager [Storeon](https://github.com/storeon/storeon) | ||
for [Corvid](https://www.wix.com/corvid) by Wix. | ||
## How to use | ||
You can use demo template to try corvid-storeon | ||
You can use demo template or install from Package Manager. | ||
- Wix Website Template: [Open In Editor](https://editor.wix.com/html/editor/web/renderer/new?siteId=d6003ab4-7b91-4fe1-b65e-55ff3baca1f4&metaSiteId=654936ba-93bc-4f97-920a-c3050dd82fe7) | ||
- [Install](#install) | ||
## Example | ||
**public/store.js** | ||
**`public/store.js`** | ||
```js | ||
@@ -31,3 +36,4 @@ import { createStore } from "corvid-storeon"; | ||
**Page Code** | ||
**`Page Code`** | ||
```js | ||
@@ -53,28 +59,49 @@ import { dispatch, connect, connectPage } from "public/store.js"; | ||
## Install | ||
You use the [Package Manager](https://support.wix.com/en/article/corvid-managing-external-code-libraries-with-the-package-manager) | ||
to manage the npm packages in your site. | ||
Latest available version: `v1.1.0` | ||
<img src="assets/cs.png" width="500" alt="Install corvid-storeon"> | ||
## API | ||
### createStore | ||
The APIs for creating modules the same as [Storeon Store](https://github.com/storeon/storeon#store) | ||
Creates a store that holds the complete state tree of your app | ||
and returns 4 methods for work with the app state. [Create Store modules API](#store). | ||
```js | ||
const { getState, dispatch, connect, connectPage } = createStore(modules); | ||
``` | ||
- `createStore(Array<Module>): Store` | ||
### getState | ||
will return current state. | ||
Returns an object that holds the complete state of your app. | ||
```js | ||
const state = getState(); | ||
``` | ||
- `getState(): object` | ||
### dispatch | ||
will emit an event with optional data. | ||
Emits an event with optional data. | ||
```js | ||
dispatch("event/type", { value: 123 }); | ||
``` | ||
- `dispatch(event: string, [data: any]): void` | ||
### connect | ||
connect to state by property key. It will return function disconnect from the store. | ||
Connects to state by property key. | ||
It will return the function disconnect from the store. | ||
```js | ||
@@ -85,3 +112,5 @@ const disconnect = connect("key", (state) => { }); | ||
``` | ||
You can connect for multiple keys, the last argument must be a function. | ||
```js | ||
@@ -96,16 +125,171 @@ connect("key1", "key2", (state) => { }); | ||
### connectPage | ||
Sets the function that runs when all the page elements have finished loading. (wrapper around `$w.onReady()`) | ||
Sets the function that runs when all the page elements have finished loading. | ||
(wrapper around `$w.onReady()`) | ||
```js | ||
connectPage((state) => { }); | ||
``` | ||
- `connectPage(initFunction: ReadyHandler): void` | ||
- `callback ReadyHandler(state: object): void` | ||
## Package Manager | ||
## Store | ||
You use the [Package Manager](https://support.wix.com/en/article/corvid-managing-external-code-libraries-with-the-package-manager) to manage the npm packages in your site. | ||
The store should be created with `createStore()` function. | ||
It accepts a list of the modules. | ||
<img src="assets/cs.png" width="500" alt="Install corvid-storeon"> | ||
Each module is just a function, which will accept a store and bind their event listeners. | ||
```js | ||
import wixWindow from "wix-window"; | ||
import { createStore } from "corvid-storeon"; | ||
// Business logic | ||
function appModule(store) { | ||
store.on("@init", () => { | ||
return { | ||
items: [], | ||
}; | ||
}); | ||
store.on("items/add", ({ items }, item) => { | ||
return { | ||
items: items.concat(item), | ||
}; | ||
}); | ||
} | ||
// Devtools | ||
function logger(store) { | ||
store.on("@dispatch", (state, [event, data]) => { | ||
if (event === "@changed") { | ||
const keys = Object.keys(data).join(', '); | ||
console.log(`changed: ${keys}`, state); | ||
} else if (typeof data !== "undefined") { | ||
console.log(`action: ${event}`, data); | ||
} else { | ||
console.log(`action: ${event}`); | ||
} | ||
}); | ||
} | ||
export default createStore([ | ||
appModule, | ||
(wixWindow.viewMode === "Preview" && logger), | ||
]); | ||
``` | ||
The store has 3 methods: | ||
- `store.get()` will return current state. The state is always an object. | ||
- `store.on(event, callback)` will add an event listener. | ||
- `store.dispatch(event, data)` will emit an event with optional data. | ||
## Events | ||
There are 4 built-in events: | ||
**`@init`** | ||
It will be fired in `createStore()`. The best moment to set an initial state. | ||
```js | ||
store.on("@init", () => { }); | ||
``` | ||
**`@ready`** | ||
> Added in: v2.0.0 | ||
It will be fired in `$w.onReady()` when all the page elements have finished loading. | ||
```js | ||
store.on("@ready", (state) => { }); | ||
``` | ||
**`@dispatch`** | ||
It will be fired on every new action (on `store.dispatch()` calls and `@changed` | ||
event). It receives an array with the event name and the event’s data. | ||
Can be useful for debugging. | ||
```js | ||
store.on("@dispatch", (state, [event, data]) => { }); | ||
``` | ||
**`@changed`** | ||
It will be fired when any event changes the state. | ||
It receives object with state changes. | ||
```js | ||
store.on("@changed", (state, data) => { }); | ||
``` | ||
You can dispatch any other events. Just do not start event names with `@`. | ||
### Reducers | ||
If the event listener returns an object, this object will update the state. | ||
You do not need to return the whole state, return an object with changed keys. | ||
```js | ||
// "products": {} will be added to state on initialization | ||
store.on("@init", () => { | ||
return { products: { } }; | ||
}); | ||
``` | ||
Event listener accepts the current state as a first argument | ||
and optional event object as a second. | ||
So event listeners can be a reducer as well. | ||
As in Redux’s reducers, you should change immutable. | ||
```js | ||
store.on("products/save", ({ products }, product) => { | ||
return { | ||
products: { ...products, [product._id]: product }, | ||
}; | ||
}); | ||
``` | ||
```js | ||
$w("#buttonAdd").onClick(() => { | ||
dispatch("products/save", { | ||
_id: uuid(), | ||
name: $w("inputName").value, | ||
}); | ||
}); | ||
``` | ||
### Async operations | ||
You can dispatch other events in event listeners. It can be useful for async operations. | ||
```js | ||
store.on("products/add", async (_, product) => { | ||
try { | ||
await wixData.save("Products", product); | ||
store.dispatch("products/save", product); | ||
} catch (error) { | ||
store.dispatch("errors/database", error); | ||
} | ||
}); | ||
``` | ||
### Unbind listener | ||
`store.on()` returns cleanup function. This function will remove the event listener. | ||
```js | ||
const unbind = store.on("@changed", () => { }); | ||
unbind(); | ||
``` | ||
## License | ||
[MIT](./LICENSE) |
14384
32.91%291
171.96%9
50%196
-3.92%