@uche-exe/pico-state v0.1.2
Pico-state: Tiny State, Big Impact
Pico-state is a lightweight state management library designed for JavaScript and TypeScript projects. It offers a simple, intuitive API for managing your application state with minimal overhead. Whether you're building a small single-page application or a more complex project, Pico-state provides the essential tools to keep your state organized and predictable.
Table of Contents
- Key Features
- Installation
- Getting Started
- API Documentation
- LocalStorage Persistence
- Examples
- Contributing
Key Features
- Lightweight: With zero dependencies and a tiny footprint, Pico-state adds minimal overhead to your project.
- Simplicity: An easy-to-learn API makes state management a breeze, even for beginners.
- Slices: Organize your state into logical slices for better maintainability and separation of concerns.
- Type Safety: Built with TypeScript from the ground up, Pico-state provides strong typing and improved code quality.
- LocalStorage Persistence: Persist your application state to
localStorage
(browser only) for seamless user experiences. - State Replacement: Replace existing state values entirely with new values.
- Asynchronous State Updates: Update state asynchronously to handle operations like fetching data and prevent UI blocking.
Installation
npm install @uche-exe/pico-state
Getting Started
1. Import Pico-state:
import { Store } from "@uche-exe/pico-state";
// Javascript
const { Store } = require("@uche-exe/pico-state");
2. Create a Store:
Initialize a new store instance with your application's initial state (initial logical Slices):
const store = new Store({
initialState: {
count: 0,
user: { name: "Alice", loggedIn: false },
products: [],
},
});
3. Create Slices:
The application state is divided into logical slices (by default) for better organization. You can add new slices at any time:
// "cart" Slice
const { cart } = store.createSlice({ name: "cart", initialState: [] });
console.log(store.state.cart); // []
// "misc" Slice
store.createSlice({ name: "misc" });
4. Access and Update State:
Use the state
getter to access the current state and setState
to update it:
// Get the current count
console.log(store.state.count); // 0
const updateCount = async () => {
// Update the "count" Slice asynchronously
await store.setState({ slice: "count", value: 1 });
};
const updateUser = async () => {
// Update the "user" Slice
await store.setState({
slice: "user",
value: {
...store.state.user,
loggedIn: true,
},
});
};
const updateStoreState = async () => {
// Update the entire state
await store.setState({
value: {
count: 2,
user: { name: "Bob", loggedIn: true },
products: [{ id: 1, name: "Laptop" }],
},
});
};
API Documentation
Store
Class
constructor(props?: StoreProps)
:Creates a new
Store
instance.props
:storeName?
: An optional name for the store, useful for debugging. Defaults to "appState
".initialState
: The initial state of the store, as a plain JavaScript object. Defaults to an empty object{}
.replace?
: When set to "true
", and a store with the specified "storeName" already exists, it will replace the existing store's state with the new "initialState
" provided. Defaults to "false
".
state: T
(getter):Returns the current state of the store. The type
T
is inferred from theinitialState
provided to the constructor.setState(props: SetStateProps<Partial<T>>): Promise<StoreState>
:Asynchronously updates the state of a specific slice or the entire store.
props
:slice?
: The name of the slice to update. If omitted, the entire store state is updated.value
: The new state value. This can be a partial update (Partial<T>
) for theslice
or the entire state.replace?
: If set to "true" without specifying aslice
, it will replace the entire store's state with the new value. Defaults to "false".
createSlice<S extends Slice>(props: CreateSliceProps<S>): Store<StoreState & { [K in keyof S]: S[K] }>
:Creates a new slice within the store.
props
:name
: The unique name of the slice (used to access it later).initialState?
: The initial state for this slice.
Returns: The
Store
instance, with the newslice
added to the state.
LocalStorage Persistence
Pico-state provides optional persistence to localStorage in browser environments. This allows your application state to be saved between sessions, providing a smoother user experience.
How it works:
- When the store is initialized, it attempts to load the state from localStorage.
- Whenever the state is updated using setState or createSlice, the new state is saved to localStorage.
Important notes:
- LocalStorage persistence is only available in browser environments.
- Be mindful of storing sensitive data in localStorage.
- Large amounts of data in localStorage can affect performance.
Examples
- Todo List: A more complex example showing how to manage a list of todo items with slices and state updates.
import { Store } from "@uche-exe/pico-state";
interface Todo {
id: number;
text: string;
completed: boolean;
}
const store = new Store({
initialState: {
todos: [] as Todo[],
},
});
const addTodo = async (text: string) => {
const newTodo: Todo = {
id: Date.now(),
text,
completed: false,
};
await store.setState({
slice: "todos",
value: [...store.state.todos, newTodo],
});
};
const toggleCompletion = async (id: number) => {
const updatedItems = store.state.todos.map((item) =>
item.id === id
? {
completed: !item.completed,
}
: item
);
const updatedState = await store.setState({
slice: "todos",
value: updatedItems,
});
};
const updateTodo = async (id: number, data: Todo) => {
const updatedItems = store.state.todos.map((item) =>
item.id === id
? {
...item,
...data,
}
: item
);
const updatedState = await store.setState({
slice: "todos",
value: updatedItems,
});
};
const deleteTodo = async (id) => {
const updatedItems = store.state.todos.filter((item) => item.id !== id);
const updatedState = await store.setState({
slice: "todos",
value: updatedItems,
});
};
Contributing
Contributions are welcome! If you find a bug, have a feature request, or want to improve the documentation, please feel free to open an issue or submit a pull request.