lom_atom
State management with error handling and reactive cache done right.
Alternative standalone implementation of eigenmethod mol_atom.
- About 11kb minified
- Memory-efficient
- Simpler, less core concept than mobx
- Loading status / error handling features
Usage examples with reactive-di: example source, demo, todomvc benchmark
Install npm install --save lom_atom
Observable property
import {mem} from 'lom_atom'
class Todo {
@mem title = ''
}
const todo = new Todo()
todo.title = '123'
Observable get/set
import {mem} from 'lom_atom'
class Todo {
@mem set title(next: string) {
}
@mem get title(): string {
return 'default'
}
}
const todo = new Todo()
todo.title = '123'
Computed values
One decorator for all cases.
class TodoList {
@mem todos = []
@mem get unfinishedTodos() {
return this.todos.filter((todo) => !todo.finished)
}
}
Like mobx, unfinishedTodos is updated automatically when a todo changed.
Side effects
Lom atom memoized property can interact with upstream (server, etc). Each observable or computed property can be used in 4 cases: get, set, cache set, cache reset. Modifiers helps to produce and control side effects for making network requests.
import {mem} from 'lom_atom'
class TodoList {
@mem set todos(todos: Todo | Error) {
fetch({
url: '/todos',
method: 'POST',
body: JSON.stringify(todos)
})
.then((data) => mem.cache(this.todos = data))
.catch(error => mem.cache(this.todos = error))
console.log('set handler')
throw new mem.Wait()
}
@mem get todos(): Todos {
console.log('get handler')
fetch('/todos')
.then((data) => mem.cache(this.todos = data))
.catch(error => mem.cache(this.todos = error))
throw new mem.Wait()
}
@mem.manual get user(): IUser {
fetch('/user')
.then((data) => mem.cache(this.user = data))
.catch(error => mem.cache(this.user = error))
}
set user(next: IUser | Error) {}
@mem todosWithUser() {
return {todos: this.todos, user: this.user}
}
}
const list = new TodoList()
this.todos
- get value, if cache is empty - invokes get todos
and actualize cache.this.todos = data
- set value, if cache empty - pass value to set todos() {}
and actualize cache.mem.cache(this.todos = data)
- set new value or error directly into cache (push).mem.cache(list.todosWithUser)
- deep reset cache for todosWithUser all its dependencies (todos) and notify all dependants about changes.@mem.manual get user() {...}
- exclude user from deep reset. mem.reset(list.todosWithUser)
resets todos but not user. If you want to reset user, use helper directly on user: mem.cache(list.user)
Key-value
Basic dictionary support. First argument is an key of any type. See eigenmethod mol_mem.
class TodoList {
@mem.key todo(id: string, next?: Todo): Todo {
if (next === undefined) {
return {}
}
return next
}
}
const list = new TodoList()
list.todo('1', {id: 1, title: 'Todo 1'})
list.todo('1')
Actions
State updates are asynchronous, but sometime we need to do transactional synced updates via action helper:
import {action, mem} from 'lom_atom'
class Some {
@mem name = ''
@mem id = ''
@action set(id: string, name: string) {
this.id = id
this.name = name
}
}
const some = new Some()
action(() => {
some.name = 'test'
some.id = '123'
})
some.set('123', 'test')