An immutable (but feeling mutable) one-way state manager without reducers
MIT License
An immutable (but feeling mutable) one-way state manager without reducers
The goal is to have a simple state manager, without being strictely related to single view library (like React or Vue). The Redux pattern, having a one-way state management, is a good pattern but Redux suffers from boilerplate, and once you add middleware you don't have clear separation of concerns. Myrtille tries to fix these drawbacks by using immer under the hood and by merging "reducers" and "reactions" into one place: listeners.
We also want to make sure your UI component tree is optimized and only refreshes when needed, that's why you can give a path
to subscribers, you can make sure your component tree will be refreshed only when this path updates.
One of the last goals that Myrtille aims at is to let the developper doing whatever he wants with this library, that's why the store is always given and usable inside your callbacks, hack-it!
npm install --save @myrtille/core
yarn add @myrtille/core
pnpm install --save @myrtille/core
package name | description | size |
---|---|---|
@myrtille/core |
base package, contains the createStore without the mutate function |
|
@myrtille/mutate |
contains the createStore WITH the mutate function, powered by immer |
|
@myrtille/react |
React.js bindings (works with core or mutate) |
createStore(initialState: Object) -> Store
const store = createStore({ todos: [] })
Store.setState(newState: Object) -> void
Store.getState() -> State
Store.mutate((state: State) -> void): void
(only available with @myrtille/mutate
version)
Store.dispatch(action: String | Object) -> void
action
is created by myrtille to follow the standard rule: { type: $yourString }
store.dispatch('FETCH_TODOS')
store.dispatch({ type: 'ADD_TODO', payload: { id: 2, label: 'new' }})
Store.addListener(action: String | Action | Function, reaction: Function((store: Store, action: Action) -> void) | void) -> Function
action
is dispatched, the registered reaction
(which is a callback) is called.reaction
at first argument, in which it will be called for every actions dispatched.Store.subscribe(path: String | Function, callback: Function(store: Store, oldState: State, action: Action) | void) -> Function
path
. The registered callback
is called whenever the store was mutated at given path
.callback
at first argument, in which it will be called for every dispatch (even if there is no mutation)''
(empty string), Β the callback will be called only for root mutationsStore.contexts: Object
addListener
and subscribe
store.contexts.firebase = require('firebase/app')
Async and mutation
{ type: 'FETCH_TODOS' }
const store = createStore({ todos: [] })
store.subscribe((store) => { console.log('new state!', store.getState()) })
// the listener to focus on
store.addListener('FETCH_TODOS', async (store) => {
const todos = await (await fetch('https://my-api/todos')).json()
store.mutate(state => {
state.todos = todos
})
})
// dispatch the listened action
store.dispatch('FETCH_TODOS')
retrieve action informations
ADD_TODO
action (that can be dispatched by a click from the UI)const store = createStore({ todos: [] })
store.subscribe((store) => { console.log('new state!', store.getState()) })
// the listener to focus on
store.addListener('ADD_TODO', (store, action) => {
store.mutate(state => {
state.todos.push(action.payload)
})
})
// dispatch the listened action
store.dispatch({ type: 'ADD_TODO', payload: { id: 2, label: 'new' } })
dispatch in a listener
@@ui/CLEAR_TODOS
(that can be dispatched by a click from the UI)CLEAR_TODOS
if todos are not already emptyconst store = createStore({ todos: [{ id: 1, label: 'finish the documentation' }] })
store.addListener((store, oldState, action) => { console.log('new action is dispatched!', action) })
store.addListener('CLEAR_TODOS', store => { store.mutate(state => { state.todos = [] }) })
// the listener to focus on
store.addListener({ type: '@@ui/CLEAR_TODOS' }, store => {
if (store.getState().todos && store.getState().todos.length > 0) {
store.dispatch('CLEAR_TODOS')
}
})
// dispatch the listened action
store.dispatch('@@ui/CLEAR_TODOS')
Please look at this documentation