lidux
v0.0.26
Published
Fast, small state management lib for React
Downloads
32
Maintainers
Readme
lidux
Fast, small state management lib for React
Basic Counter
import React from "react";
import { dispatch, model, component } from "lidux";
// create model with default value 0
const count = model(0);
// define an action that modifies count model
// just simple increase count value by 1
const Increase = () => count.add(1);
// define component
const App = component(() => (
<>
{/* display count model value */}
<h1>{count()}</h1>
{/* dispatch Increase action when the button is clicked */}
<button onClick={() => dispatch(Increase)}>Increase</button>
</>
));
Define models
Model is where you can store your single value. You can update model values when action dispatches. If you try to update model values outside action dispatching, no UI component re-render
import { model } from "lidux";
const num = model(1);
console.log(num()); // 1
num.add(2);
console.log(num()); // 3
const bool = model(true);
bool.toggle();
console.log(bool()); // false
When you update object/array model, no mutation applied on original value, new array/object will be cloned from original value and re-assign to model value after mutating
import { model } from "lidux";
const originalArr = [1, 2];
const arr = model(originalArr);
arr.push(3, 4);
console.log(arr()); // [1, 2, 3, 4]
console.log(originalArr === arr()); // false
const originalObj = { name: "A" };
const obj = model(originalObj);
obj.set("name", "B");
console.log(obj()); // { name: 'B' }
console.log(originalObj === obj()); // false
Dispatching an action
Action is just simple function with single argument
import { dispatch } from "lidux";
const Action = context => {
// do something
console.log(context.payload); // 100
};
dispatch(Action, 100);
Handle Async Action
Action body can be sync/async function. We can use context.dispatch to dispatch another action inside current action execution
const Increase = ({ payload }) => count.add(payload);
const IncreaseAsync = async context => {
// delay current execution in 1000ms
await context.delay(1000);
context.dispatch(Increase, context.payload);
};
Action Context References
context.dispatch(action, payload)
Dispatches another action inside current action execution
context.until(...actions) => Promise
Returns a promise that will be resolved when one of specified actions is dispatched
context.delay(ms) => Promise
Returns a promise that will be resolved in specified milliseconds
context.race(promises) => Promise
Returns a promise that will be resolved when one of specified promises is resolved
import { model, dispatch } from "lidux";
const profileModel = model(undefined);
const CallProfileApi = () => {};
const LoadProfile = async ({ cancelled }) => {
// load profile from API
const profile = await CallProfileApi();
if (cancelled()) {
return;
}
// update profile to model
profileModel(profile);
};
const Login = () => {};
const Logout = () => {};
const Startup = async ({ until, race, dispatch }) => {
// create infinite loop that handles Login, Logout actions dispatching
while (true) {
// wait until Login action dispatched
await until(Login);
const { key } = race({
logout: until(Logout),
profile: dispatch(LoadProfile)
});
if (key === "logout") {
// a Logout action is dispatched that means LoadProfile action execution should be cancelled
} else if (key === "profile") {
// profile loaded successfully
// start waiting for Logout action
await until(Logout);
// continue waiting for Login action in next loop
}
}
};
dispatch(Startup);
context.all(promises) => Promise
Returns a promise that will be resolved when all specified promises are resolved
const LoadData = async ({ dispatch, all }) => {
const result = await all({
profile: dispatch(LoadProfile),
products: dispatch(LoadProducts)
});
console.log(result.profile);
console.log(result.products);
};
If one of specified promises is rejected, another promises / async executions will be cancelled as well
const LoadData = async ({ dispatch, all }) => {
const result = await all({
profile: dispatch(LoadProfile),
products: dispatch(LoadProducts),
noop: Promise.reject("reason")
});
// unreachable code
};
context.allSettled(promises) => Promise
context.subscribe(listener) => Function;
context.subscribe(actions, listener) => Function;
context.debounce(ms, func) => Function
context.throttle(ms, func) => Function
context.latest(func) => Function
Model References
model.value
Get and set current value of model
arrayModel.push(...elements)
Add one or more elements to the end of an array
arrayModel.unshift(...elements)
Add one or more elements to the beginning of an array
arrayModel.sort(compareFunction)
Sort the elements of an array in place
arrayModel.splice(start, deleteCount, ...elements)
Change the contents of an array by removing or replacing existing elements and/or adding new elements
arrayModel.pop()
Remove the last element from an array
arrayModel.filter(predicate)
Filter out all elements that don't pass the provided predicate function
numberModel.add(by)
Add current number by specified value
dateModel.add(milliseconds)
Increase current date by specified milliseconds
dateModel.add(duration)
Increase current date by specified duration. The duration is object that includes following properties: years, months, days, minutes, hours, seconds, milliseconds
booleanModel.toggle()
Reverse the logical (true <=> false) state of the model value
stringModel.append(...values)
Append values to the current string
stringModel.prepend(...values)
Prepend values to the current string
objectModel.set(prop, value)
Assign new property value of the current object
objectModel.unset(...propNames)
Unset all specified properties of the current object
objectModel.assign(...sources)
Copy all enumerable own properties from one or more source objects to the current object