Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

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

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}




)

}
```