Zustand is a lightweight state manager for javascript applications
npm install zustand zustand-lit
Version 2.0.0 breaking changes!
- Removed
observedecorator - Removed
connectmixin function - Added
watchandwatchWithSelectordecorators
Motivation:
The connect and observe adapters update the component whenever the state changes. On top of that unnecessary renders are happened. To avoid this problems the new watchWithSelector API was created.
You have to use createStore factory function from zustand/vanilla package.
- Choose
@watchif you have no many data and/or for static objects (like config, user, etc.) - Choose
@watchWithSelectorfor performance control - Choose
Context APIto create 3d party library
import { LitElement, html } from 'lit';
import { customElement } from 'lit/decorators.js';
import { createStore } from 'zustand/vanilla';
import { watch } from 'zustand-lit';
interface BearState {
bears: number;
addBear: () => void;
}
const BearStore = createStore<BearState>(set => ({
bears: 0,
addBear: () => set(state => ({ bears: state.bears + 1 })),
}));
@customElement('bears')
class BearsElement extends LitElement {
@watch(BearStore) state?: BearState;
render() {
return html`
<p>${this.state?.bears}</p>
<button @click=${this.state?.addBear}>
Add bear
</button>
`;
}
}To control renders you are able to use watchWithSelector decorator
import { watchWithSelector } from 'zustand-lit';
interface ZooState {
bears: number;
cows: number;
monkeys: number;
snakes: number;
}
const selectBears = (state: ZooState) => state.bears;
@customElement('bears')
class BearsElement extends LitElement {
@watchWithSelector({ store: ZooStore, selector: selectBears })
bears?: number;
}| Parameter | Mandatory | Default | Description |
|---|---|---|---|
| store | Yes | - | Store object created by createStore |
| selector | Yes | - | A state extractor |
| equalityFn | No | Object.is |
A function that lets you skip re-renders |
Before using context api you have to install @lit/context package.
For more information take a look at the docs
Usage
@withZustandProviderto create provider component@consumefrom@lit/contextto read store value@consumeWithSelectorfor performance controlupdateState(context, value)to update state
import { LitElement, html } from 'lit';
import { customElement } from 'lit/decorators.js';
import { consume, createContext } from '@lit/context';
import { withZustandProvider, updateState } from 'zustand-lit/context';
interface BearState {
bears: number;
}
const initialState: BearState = {
bears: 0
};
const BearContext = createContext<BearState>('bear-context');
@customElement('bears-provider')
@withZustandProvider({ context: BearContext, initialState })
class BearsProvider extends LitElement {
render() {
return html`<bears-consumer></bears-consumer>`;
}
}
@customElement('bears-consumer')
class BearsConsumer extends LitElement {
@consume({ context: BearContext, subscribe: true })
state?: BearsState;
addBears() {
const current = this.state?.bears ?? 0;
updateState(BearContext, { bears: current + 1 });
}
render() {
return html`
<p>${this.state?.bears}</p>
<button @click=${this.addBears}>
Add bear
</button>
`;
}
}To control renders you are able to use consumeWithSelector decorator
import { consumeWithSelector } from 'zustand-lit/context';
interface ZooState {
bears: number;
cows: number;
monkeys: number;
snakes: number;
}
const selector = (state: ZooState): number => state.bears;
@customElement('bears-consumer')
class BearsConsumer extends LitElement {
@consumeWithSelector({ context: BearContext, selector })
bears?: number;
}consumeWithSelector options
| Parameter | Mandatory | Default | Description |
|---|---|---|---|
| context | Yes | - | Context object created by createContext |
| selector | Yes | - | A state extractor |
| equalityFn | No | Object.is |
A function that lets you skip re-renders |
This project is licensed under the MIT License - see the LICENSE file for details