Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/panmanfredini/lit-element-effector
Mixin to add an Effector Store to lit-element
https://github.com/panmanfredini/lit-element-effector
effector lit-element
Last synced: 12 days ago
JSON representation
Mixin to add an Effector Store to lit-element
- Host: GitHub
- URL: https://github.com/panmanfredini/lit-element-effector
- Owner: panManfredini
- License: mit
- Created: 2020-10-22T18:56:02.000Z (over 4 years ago)
- Default Branch: main
- Last Pushed: 2020-10-30T22:26:45.000Z (about 4 years ago)
- Last Synced: 2024-04-24T22:43:01.923Z (9 months ago)
- Topics: effector, lit-element
- Language: JavaScript
- Homepage:
- Size: 120 KB
- Stars: 7
- Watchers: 1
- Forks: 0
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# lit-element-effector
Minimal mixin to attach an [Effector](https://effector.now.sh/) Store to [lit-element](https://lit-element.polymer-project.org/).- Automatically request element update on effector store change.
- Supports typescript.
- Just a tiny wrapper, about [1kB minified](https://bundlephobia.com/result?p=lit-element-effector@latest).
- Supports a pattern for inheritance.
- Safe: makes a copy of the store into the custom element.
- Built with best practices in mind.**/!\ currently there is an [issue](https://github.com/panManfredini/lit-element-effector/issues/2) with ts-loader, but rollup and standalone webpack work.**
# Usage
```ts
EffectorMxn( BaseClass, Store, FxAPI? ) => class extends BaseClass
```
The mixin takes as input parameters a `BaseClass` which must inherit from a `LitElement`, an Effector `Store` and an optional object, `FxAPI`.
This last one is meant as dependency injection of the custom-element's effect interface, its values are expected to be
either effector `effects` or `events` (or functions).```js
import {EffectorMxn} from "lit-element-effector"
import {html, LitElement} from "lit-element"
import {createStore} from "effector"const store01 = createStore( {greetings:"hello"} );
class example01 extends EffectorMxn( LitElement, store ){
render(){
// the store state is available with the `$` property
return html`${this.$.greetings} world!
`
}
}customElements.define("example-01",example01);
```
The provided store is reflected to the LitElement property **$**. Supports any store types, from boolean to objects.
The store state is deeply-copied to **$**. Direct assignment to the property **$** should be avoided, altough it cannot affect the state.## Event and Effect API Helper
```js
import {createEvent, createEffect} from "effector"const evnt = createEvent();
const Fx = createEffect(/* some network call*/);store01.on( evnt, (_,p) => { return {greetings:p} } );
const API = { changeGreetings: evnt, networkCallFx: Fx } ;
class example02 extends EffectorMxn(LitElement, store01, API){
render(){
return html`
${this.$.greetings} world!
`
}clickme(){
// the effects API is available under `dispatch` prop
this.dispatch.changeGreetings("Hey");
}
}```
If defined, the effect API is injected into the `dispatch` getter property. This is no more than a recommendation,
it helps to keep the custom-element decoupled from the app-state (see an example in the test section below).
In some cases can be more convenient to override the `dispatch` getter, if you do so is a good practice to return
a shallow copy of the API object (since it could be used in multiple places).## React on Store change with user defined function
```js
class example03 extends EffectorMxn(LitElement, store){
on_store_update(stateCopy)
{
/* Do something on update */
}
render() { /* render component */ }
}
```If defined, the function `on_store_update` will be executed any time a store change is triggered.
The only argument passed to the function is a copy of the current store. This function will run after the property **$** is
set, but before any of the element's update/render.## Inheritance
```js
import {combine} from "effector";
const store02 = createStore( {username:"Alex"} )
const combinedStore = combine(store01,store02, (a,b) => Object.assign({}, a,b) );// here applying the mixing to the previous example class
class example04 extends EffectorMxn(example01, combinedStore){
// adding a reflected attribute on top of the inherited ones
@property() type = "dark";
render(){
return html `
${super.render()}
This is ${this.$.username}.
`
}
}```
LitElement makes sure that reflected properties of inherited classes are present and functioning. One thing to notice is that when
applying the mixin multiple times the store is actually swapped, so the provided store of a child class must be a combination
of the parent store and the additional wanted properties.## Testing Helpers
```ts
it("Detaches from current store, send fake data", async ()=>{var ex01 = document.createElement("example-01");
// this detaches from store (replace with undefined)
ex01.replaceStore();
//ex01.replaceStore(newStore);// the element is not initialized until it is connected
document.body.appendChild(ex01);
await ex01.updateComplete; // wait for renderexpect(ex01.$).to.be.undefined; // no store
// simulate a store update with fake data
ex01.store_update_handler( {greetings: "Ciao" } );expect(ex01.$).to.deep.equal( {greetings: "Ciao" } );
});```
There are a few convenient helpers to aid testing a custom-element with attached store. A function `replaceStore` is provided to swap the store with a fake one.
The `store_update_handler` function can be used to simulate a store update with fake data, you can also use this to initialize the element before appending the element to DOM.```js
it("Reassign the event API of an instance",()=>{
customElements.define("example-02",example02);
var ex02 = document.createElement("example-02");
ex02.dispatch.networkCallFx = ( ) => {};document.body.appendChild(ex02);
/* go on with network related call disabled */
});
```
Many times during testing we would mock or stub effects that make network calls, here you can simply reassign the instance API injecting a different function.
The `dispatch` getter returns a shallow copy of the effect-API, this means that you can swap the keys of that instance with fakes without
affecting the overall element class nor the original effect-API.