Flexible and easy unidirectional store library for state management with Dependency Injection for React or other frontend apps.
DEMO with React in Typescript
This project is React binding of Memento.NET
You can define stores inspired by MVU patterns such as Flux and Elm to observe state changes more detail.
Some are inspired by Elm and MVU. And Redux and Flux pattern are same too, but memento is not Redux and Flux.
- Less boilarplate and simple usage
- Is not flux or redux
- Observe detailed status with command patterns and makes it easier to monitor what happened within the application
- Immutable and Unidirectional data flow
- Multiple stores but manged by single provider, so can observe and manage as one state tree
- Less rules have been established
- You can choose between a simple store pattern or a dispatch reducer pattern like Flux or MVU
Note the concept is a bit different from Flux and Redux
- mutate method mutates a store state
- To change state our app should Dispatch via Reducer in the action method
- Every Reducer that processes in the action will create new state to reflect the old state combined with the changes expected for the action.
- State should always be read-only.
- The UI then uses the new state to render its display.
Here is a sample of simple store pattern
import { LiteStore } from "memento.react"
const delay = (timeout: number) =>
new Promise(resolve => setTimeout(resolve, timeout))
const simpleState = {
count: 0,
history: [],
isLoading: false,
}
@meta({ name: "SimpleStore" })
export class SimpleStore extends LiteStore<typeof simpleState> {
constructor() {
super(simpleState)
}
async countUpAsync() {
this.setState({
...this.state,
isLoading: true,
})
await delay(500)
const state = this.state
const count = state.count + 1
this.setState({
...state,
history: [...state.history, count],
count,
isLoading: false,
})
}
setCount(num: number) {
this.setState({
...this.state, count: num,
history: [...this.state.history, num]
})
}
async delay(timeout: number) {
await new Promise(resolve => setTimeout(resolve, timeout))
}
}
import {
useObserver,
useDispatch,
} from "memento.react"
import React, {useState } from "react"
export const SimpleStoreView = () => {dedux
// store state
const counter = useObserver(SimpleStore)
const dispatch = useDispatch(SimpleStore)
// store state with sliced by selector
const history = useObserver(SimpleStore, state => state.history)
// local state
const [toAdd, setToAdd] = useState(1)
const handleClick = () => {
dispatch(store => store.countUpAsync())
}
const handleSet = () => {
dispatch(store => store.setCount(counter.count + toAdd))
setToAdd(1)
}
return (
<div style={{
display: "flex",
flexDirection: "column",
alignItems: "center"
}}>
<h2>Counter</h2>
<p>{counter.count}</p>
<button onClick={handleClick}>
Count UP
</button>
<div style={{
display: "flex",
alignItems: "center",
justifyContent: "space-between",
width: "260px"
}}>
<p>{counter.count}</p>
<div style={{ flex: "1 1 auto" }} />
<p>+</p>
<div style={{ flex: "1 1 auto" }} />
<input
type="number"
value={toAdd}
onChange={e => setToAdd(Number(e.target.value))}
/>
<button onClick={handleSet}>
Calc
</button>
</div>
<h4>Loading : {counter.isLoading ? "YES" : "NO"}</h4>
<h4>History</h4>
<div
style={{
height: "300px",
width: "400px",
overflowY: "auto",
background: "rgba(0,0,0,0.08)",
textAlign:"center",
}}
>
{
!history.length && <p>No history</p>
}
{
history.map(h =>
<p key={h}>history: {h}</p>
)
}
</div>
</div>
)
}
Package Name | Version | Lang | Platform | Package manager | Release Notes | Package provider |
---|---|---|---|---|---|---|
memento.core | 1.0.3 | TS/JS | node.js 14 or later | npm or yarn | Notes | npm |
memento.react | 1.0.4 | TS/JS | node.js 14 or later | npm or yarn | Notes | npm |
Basic Concept with Typescript/Javascript
Here is a demo site built with React in Typescript. DEMO
Designed with ♥ by le-nn. Licensed under the MIT License.