Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/simmor-store/simmor
Simple immutable boilerplate-free state management
https://github.com/simmor-store/simmor
angular immer react rxjs store
Last synced: about 2 months ago
JSON representation
Simple immutable boilerplate-free state management
- Host: GitHub
- URL: https://github.com/simmor-store/simmor
- Owner: simmor-store
- License: mit
- Created: 2019-09-22T16:08:20.000Z (over 5 years ago)
- Default Branch: master
- Last Pushed: 2023-01-04T11:05:32.000Z (about 2 years ago)
- Last Synced: 2024-11-23T09:04:14.570Z (about 2 months ago)
- Topics: angular, immer, react, rxjs, store
- Language: TypeScript
- Homepage:
- Size: 624 KB
- Stars: 3
- Watchers: 2
- Forks: 1
- Open Issues: 14
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
Simmor is a simple immutable boilerplate-free framework-agnostic store with support of middlewares and state slicing.
# Install
`npm install simmor`# Examples
* [React](https://github.com/simmor-store/react-simmor)
* [Angular](https://github.com/simmor-store/angular-simmor-examples)# Online demo
[https://codesandbox.io/s/github/simmor-store/react-simmor/tree/master/examples](https://codesandbox.io/s/github/simmor-store/react-simmor/tree/master/examples)
# React examples
The simplest way to use simmor is by creating a localStore.
Here an example of counter store that has state `{value: number}`.
State can be modified throw `draft` field. Simmor uses [immer](https://github.com/immerjs/immer) that can update immutable state by mutating it.
```ts
const [state, dispatch] = useLocalStore({value: 0}, ctx => ({
increase() {
ctx.draft.value += 1
},
decrease() {
const newValue = ctx.draft.value - 1
if (newValue >= 0) {
ctx.draft.value = newValue
}
},
increaseWithDelay() {
setTimeout(() => this.increase(), 300)
},
setValue(value: number) {
ctx.draft.value = value
}
}))```
```ts
{state.value}
dispatch.increase()}>+
dispatch.decrease()}>-
dispatch.setValue(0)}>reset
dispatch.increaseWithDelay()}>Increase with delay
```
# Store class
We can define store as class.```ts
export type CounterState = { value: number }export class CounterStore extends ReducerStore {
increase() {
this.draft.value += 1
}decrease() {
const newValue = this.draft.value - 1
if (newValue >= 0) {
this.draft.value = newValue
}
}setValue(value: number) {
this.draft.value = value
}
}```
```ts
export const Counter = ({store}: { store: CounterStore }) => {
const value = useStore(store, x => x.value)
return (
{value}
store.increase()}>+
store.decrease()}>-
store.setValue(0)}>Reset
)
}```
```ts
const store = new CounterStore({value: 0})```
# Middleware
Simmor supports middlewares. Here an example of middleware that saves state to localStorage.
```ts
export function createLocalStorageMiddleware(key: string): Middleware {
return next => action => {
const newState = next(action)
if (action.methodName === "constructor") {
const savedState = localStorage.getItem(key)
if (savedState) {
return JSON.parse(savedState)
}
}
localStorage.setItem(key, JSON.stringify(newState))
return newState
}
}```
We can pass middlewares in the constructor of the store and our component can now save its state between sessions.```ts
const persistentStore = new CounterStore({value: 0}, {
middlewares: [createLocalStorageMiddleware('counter')]
})```
# State slicing
It is possible to slice a part of the state.
For example if we need two counters and we want to swap values between them.```ts
type CounterPairState = {
left: CounterState
right: CounterState
}export class CounterPairStore extends ReducerStore {
leftStore = new CounterStore(this.slice('left'))
rightStore = new CounterStore(this.slice('right'))constructor() {
super({left: {value: 100}, right: {value: 200}})
}swap() {
const [leftValue, rightValue] = [this.state.left.value, this.state.right.value]
this.leftStore.setValue(rightValue)
this.rightStore.setValue(leftValue)
}static sum(state: CounterPairState) {
return state.left.value + state.right.value
}
}```
And the component
```ts
const store = new CounterPairStore()
export const CounterPair = () => {
const state = useStore(store, x => x)
const sum = CounterPairStore.sum(state)return (
store.swap()}>swap
Sum {sum}
)}
```