aio-store
v2.5.2
Published
A javascript app state management
Downloads
35
Maintainers
Readme
AIO-STORE
State management for any javascript application. It's tiny, fast, stable, contains no boilerplate, has no side effects, doesn't need a context provider and compatible with SSR. It comes with zero dependencies and lets you dispatch actions from anywhere. Typescript user or Javascript user, it doesn't matter. It is all for you.
Installation
npm install aio-store
Usage
Let's import createStore
// All users, No hook
import { createStore } from "aio-store";
// React user with hook
import { createStore } from "aio-store/react";
Create a store
Just create your store, No actions is needed
export const useExpStore = createStore({
exp: 10,
});
Use the store
- Anywhere in your app
const store = myStore.get()
- Inside a React component
import { useExpStore } from "./store";
const MyComponent = () => {
// Realtime update for React users
const { exp } = useExpStore();
// ❗ this is just a snapshot, No realtime changes
const { exp } = useExpStore.get();
// ❗ this is just a snapshot, No realtime changes
const exp = useExpStore.get("exp");
// Realtime update available for React users
const { exp } = useExpStore("*");
// Deep data with realtime update
const deepValue = useExpStore("data.depp.moreDeep");
return <span>{exp}</span>;
};
- With selector
Get your store and return whatever you want in any format
import { useExpStore } from "./store";
const MyComponent = () => {
const { exp } = useExpStore(store => ({exp: store.exp}));
const [exp,other] = useExpStore(store => [store.exp,store.other]);
const exp = useExpStore(store => store.exp);
// Deep data with realtime update
const deepValue = useExpStore(store => store.data.depp.moreDeep);
// ❗ Just a snapshot, No realtime changes
const exp = useExpStore.get(store => store.exp);
return <span>{exp}</span>;
};
- With listener
You can listen to your store changes anywhere in your app and update something stateless. Very useful when you want to eliminate unnecessary rendering.
const myStore = createStore(...);
// Listen to all changes
myStore.listen('*', (data) => {
// while listening, you can get a snapshot to do some control
// React user or vanilla users
const snap = myStore.get()
// vanilla users
const snap = myStore()
const someValue = myStore.get("someValue")
// do what ever you want with your data,
})
// Listen to specific changes
myStore.listen('data.content.value', (data) => {
// while listening, you can get a snapshot
const snap = myStore.get()
const someValue = myStore.get("someValue")
// do what ever you want with your data,
})
The listen method returns an unsubscribe function
const unsubscribe = myStore.listen('data', (data) => {})
unsubscribe()
Limit render
By default aio-store
use strict equality to prevent unnecessary render.
For more control, you can use any data equality function as long as it returns a boolean.
// String selector
const data = myStore("data",(oldValue, newValue) => sameOrNot)
// Function selector
const data = myStore(store => store.data, (oldValue, newValue) => sameOrNot)
// Listener selector
const data = myStore("data",callback, (oldValue, newValue) => sameOrNot)
Mutation
Your store is immutable, you will always get a fresh store.
When you mutate your store, Please be aware that, storeRef
or whatever the name you call it, point to a reference of your store.
So do not override the reference.
Mutate Object
const myStore = createStore({
myValue: 10,
})
myStore.set(storeRef => {
// ❌ Bad, Don't do this.
storeRef = {
myValue: 11
}
})
Instead, do like following lines
const myStore = createStore({
myValue: 10,
})
myStore.set(storeRef => {
storeRef.MyValue = 11
// ✅ Good,
storeRef.MyValue = {
// ...whatever you want
}
// ✅ Good, you can add new Props
storeRef.newProp = {
// ...whatever you want
}
// ✅ Good,
storeRef.props.data = {
someData: someValue
// ...whatever you want
}
// ✅ Good, if props.data already exists
storeRef.props.data.someData += someValue
})
Mutate Array
const myStore = createStore({
arr: [{name: "default"}],
})
myStore.set(storeRef => {
// Mutation inside the array
storeRef.arr[0].name = "New name";
storeRef.arr.push("new item")
// Mutation with new array or clean the array
storeRef.arr.length = 0
// Or
storeRef.arr = []
})
Mutate Map / Set
const myStore = createStore({
map: new Map(),
set: new Set(),
setContainsMap: new Set().add(new Map()),
mapContainsSet: new Map().set("mySet",new Set()),
})
// Mutation inside the array
myStore.set(storeRef => {
// Mutation inside a map
storeRef.map.set("new Key", "new value")
// Mutation inside a set
storeRef.set.add("new value")
// Mutation inside setContainsMap
storeRef.setContainsMap.forEach(s => {
// S is a Map
s.set("new Key", "new value")
})
// Mutation inside mapContainsSet
storeRef.mapContainsSet.get("mySet").add("new Value")
// Cleaning
storeRef.mapContainsSet.clear()
storeRef.setContainsMap.clear()
})
Transferring the ref
When you do not want to repeat yourself, It is useful to save a reference of the updated part and use it multiple times. But always take care of not destroying that reference
const myStore = createStore({
data: {
deep: {
moreDeep: {}
}
}
})
myStore.set(storeRef => {
const moreDeep = storeRef.data.deep.moreDeep;
// Use moreDeep ✅
moreDeep.newProp1 = "new value 1"
moreDeep.newProp2 = "new value 2"
let deep = storeRef.data.deep;
// Use moreDeep ✅
deep.moreDeep = {
newProp1: "new value 1",
newProp2: "new value 2"
}
let moreDeep = storeRef.data.deep.moreDeep;
// ❌ you are destroying the reference.
// ❌ moreDeep is not pointing anymore the real moreDeep.
// ❌ It has a new reference
moreDeep = {
newProp1: "new value 1",
newProp2: "new value 2"
}
// But This is fine ✅
// Because the storeRef is in charge
storeRef.data.deep.moreDeep = {
newProp1: "new value 1",
newProp2: "new value 2"
}
})
Available tools and options
createStore
Let you create a storeset
A property attached to your store that lets you dispatch actions from any file.get
A Function attached to your store that lets you get a snapshot of your store at any time.listen
A Function attached to your store that lets you listen to changes in all or specific part of your store.*
A key that can be passed to your store in order to get everything or to listen to all changes in your store.