Gathering detailed insights and metrics for arbor-store
Gathering detailed insights and metrics for arbor-store
Gathering detailed insights and metrics for arbor-store
Gathering detailed insights and metrics for arbor-store
@arborjs/store
A fully typed, minimalistic proxy-based state tree library with very little boilerplate.
@arborjs/plugins
Community driven plugins for @arborjs/store.
@arborjs/rxjs
rxjs binding for @arborjs/store
arbor-react
Provides a connect function to link an Arbor store with a React component
npm install arbor-store
Typescript
Module System
47.7
Supply Chain
90.3
Quality
75.8
Maintenance
100
Vulnerability
100
License
JavaScript (100%)
Total Downloads
4,832
Last Day
1
Last Week
6
Last Month
70
Last Year
486
8 Stars
29 Commits
6 Watchers
2 Branches
3 Contributors
Updated on Apr 28, 2023
Latest Version
0.5.0
Package Id
arbor-store@0.5.0
Unpacked Size
23.45 kB
Size
9.69 kB
File Count
8
Cumulative downloads
Total Downloads
Last Day
0%
1
Compared to previous day
Last Week
-80.6%
6
Compared to previous week
Last Month
45.8%
70
Compared to previous month
Last Year
-19.1%
486
Compared to previous year
19
Seamless state management made with ❤️.
Arbor is a state tree management solution that leverages immutability through structural sharing to perform state tree mutations allowing subscribers to listen to state changes.
Even though immutability is Arbor's foundation, very little boilerplate is added to the developer's workflow and mutations are triggered via the old and familiar Javascript Object/Array APIs (thanks to ES6 Proxies under the hoods). Because Arbor mutations apply structural sharing under the hoods, features like state history playback and undos are easily implemented.
Additionally, Arbor allows custom types to be bound the specific paths within the state tree so you may better encapsulate your business logic keeping them separate from UI logic, increasing testability as well as business logic reusability.
Arbor is framework agnostic, though, there is a React binding that you can check out.
A simple Counter APP...
1import Arbor from "arbor-store" 2 3const store = new Arbor({ 4 counter1: { 5 count: 0, 6 }, 7 counter2: { 8 count: 0, 9 } 10}) 11 12store.subscribe((nextState, previousState) => { 13 console.log("new state:", nextState) 14 console.log("old state:", previousState) 15}) 16 17store.state.counter1.count++
1const store = new Arbor({ 2 counter1: { 3 count: 0, 4 }, 5 counter2: { 6 count: 0, 7 } 8})
The snippet above defines a store whose state tree looks like this:
(root)
/ \
(counter1) (counter2)
| |
count = 0 count = 0
In the state tree, (root)
, (counter1)
and (counter2)
are tree node objects responsible for all the immutability "magic". Each node has a path that determines its location within the state tree. (root)
for example is represented by the /
path, (counter1)
is represented by /counter1
and (counter2)
represented by /counter2
. Leaf nodes within the state tree are non-node types (count
attributes).
The code below registers a subscriber function which is called whenever a mutation happens in the state tree, providing access to the next and previous states.
1store.subscribe((nextState, previousState) => { 2 console.log("new state:", nextState) 3 console.log("old state:", previousState) 4})
1store.state.counter1.count++
Every mutation triggered by any node creates a mutation path that determines which nodes in the state tree were affected by the mutation and thus must be refreshed with new instances.
Once a mutation is finished, a new state tree is generated where nodes affected by the mutation path have their instances refreshed and nodes not affected by the mutation path are kept untouched (Structural Sharing), for instance:
Triggers a mutation in the state tree for the mutation path /counter1
. That mutation path affects the (root)
node whose path is /
, and the (counter1)
node whose path is /counter1
. Since (counter2)
whose path is /counter2
is not affected by the mutation path, it is reused in the new state tree:
(root*)
/ \
(counter1*) (counter2)
| |
count = 1 count = 0
Nodes marked with a *
in the state tree above represent the nodes affected by the mutation path and thus are new node instances.
As React applications grow larger, splitting business and UI logic can get tricky. Arbor allows custom node types to be bound to specific paths within the state tree, where business logic code can be encapsulated increasing testability and maintainability.
Custom node types are just plain ES6 classes that are explicitly bound to certain paths of the state tree and provide a constructor which "selects" what state attributes it cares about, for example:
1class Todo { 2 constructor({ id, title, status }) { 3 this.id = id 4 this.title = title 5 this.status = status 6 } 7 8 start() { 9 this.status = "doing" 10 } 11 12 finish() { 13 this.status = "done" 14 } 15 } 16 17 const store = new Arbor({ 18 todos: [ 19 { id: 1, title: "Do the dishes", status: "todo" }, 20 { id: 2, title: "Clean the house", status: "todo" } 21 ] 22 }) 23 24 store.bind("/todos/:index", Todo)
The example above defines a custom node type Todo
and binds it to the /todos/:index
path. There are a few things to notice here:
Todo
implements a constructor which takes all properties that make up a todo item.:index
represents any todo item within the todos array. Any access to any todo item in the array, will yield an instance of Todo
, e.g.:1const todo = store.state.todos[0] 2expect(todo).to.be.an.instanceOf(Todo)
Custom node types can represent either objects or array nodes within the State Tree. Custom array nodes must extend Array
:
1class Todos extends Array { 2 constructor(items) { 3 super(...items) 4 } 5 6 createTodo({ title }) { 7 this.push({ id: Math.random(), title }) 8 } 9 10 startTodo(index) { 11 this[index].start() 12 } 13 14 finishTodo(index) { 15 this[index].finish() 16 } 17 18 sortByTitle() { 19 this.sort((todo1, todo2) => { 20 if (todo1.title > todo2.title) return 1 21 if (todo1.title < todo2.title) return -1 22 return 0 23 }) 24 } 25} 26 27store.bind("/todos", Todos)
Arbor leverages Structural Sharing in order to perform state mutations. A new state tree is always created by applying the minimum amount of operations necessary to generate the new state. With this, a series of state snapshots may be recorded, allowing for interesting use cases such as State Time Travel.
MIT
No vulnerabilities found.
Reason
no binaries found in the repo
Reason
0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Reason
Found 0/29 approved changesets -- score normalized to 0
Reason
no SAST tool detected
Details
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
security policy file not detected
Details
Reason
license file not detected
Details
Reason
project is not fuzzed
Details
Reason
branch protection not enabled on development/release branches
Details
Reason
106 existing vulnerabilities detected
Details
Score
Last Scanned on 2025-05-05
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
Learn More