controllex
v0.0.2-alpha
Published
A simple, predictable state management library for JavaScript applications
Downloads
201
Maintainers
Readme
Why ControlleX?
ControlleX is a framework-agnostic state management library designed for developers who want:
- ✨ Simplicity — Get started in minutes, not hours
- 🎯 Predictability — Explicit state changes, easy debugging
- 📦 Zero dependencies — Just pure JavaScript
- 🔌 Framework adapters — React support built-in, Vue/Angular coming soon
- 💾 Persistence — Built-in localStorage plugin
Unlike complex solutions like Redux, ControlleX requires no boilerplate, no action constants, and no middleware setup.
Installation
npm install controllexQuick Start
Level 1: Ultra Simple (For Beginners)
import { createStore } from 'controllex';
// Create a store with initial state
const store = createStore({
initialState: {
count: 0,
user: null
}
});
// Read state
console.log(store.getState().count); // 0
// Update state
store.setState({ count: 1 });
// Update with current state
store.setState(state => ({ count: state.count + 1 }));
// Subscribe to changes
const unsubscribe = store.subscribe(() => {
console.log('State changed:', store.getState());
});
// Stop listening
unsubscribe();With React
import { createStore } from 'controllex';
import { useStore } from 'controllex/react';
// Create your store
const counterStore = createStore({
initialState: { count: 0 }
});
// Use in components
function Counter() {
const count = useStore(counterStore, state => state.count);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => counterStore.setState(s => ({ count: s.count + 1 }))}>
Increment
</button>
</div>
);
}Level 2: Advanced Usage (For Larger Apps)
Using Slices
Organize your state into logical slices:
import { createSlice, createStore } from 'controllex';
// Define a counter slice
const counterSlice = createSlice({
name: 'counter',
initialState: { value: 0 },
reducers: {
increment: (state) => ({ ...state, value: state.value + 1 }),
decrement: (state) => ({ ...state, value: state.value - 1 }),
incrementBy: (state, amount: number) => ({
...state,
value: state.value + amount
}),
}
});
// Create store with the slice's initial state
const store = createStore({
initialState: counterSlice.getInitialState()
});
// Use auto-generated actions
const action = counterSlice.actions.increment();
const newState = counterSlice.reducer(store.getState(), action);
store.setState(newState);Persistence
Keep your state across page reloads:
import { createStore } from 'controllex';
import { persist } from 'controllex/plugins';
const store = createStore({
initialState: {
theme: 'dark',
user: null,
temporaryData: []
}
});
// Persist only specific keys
const persistedStore = persist(store, {
key: 'my-app-state',
whitelist: ['theme', 'user'], // Don't persist temporaryData
});Documentation
Full documentation is available in the /docs/en folder:
- Index — Welcome to ControlleX!
- Introduction — What is ControlleX?
- Core Concepts — Understanding stores and state
- Beginner Guide — Step-by-step tutorial
- Advanced Usage — Slices, plugins, and patterns
- Adapters — React, Vue, Angular integration
Examples
Todo App
import { createStore } from 'controllex';
interface Todo {
id: number;
text: string;
completed: boolean;
}
const todoStore = createStore({
initialState: {
todos: [] as Todo[],
filter: 'all' as 'all' | 'active' | 'completed'
}
});
// Add todo
const addTodo = (text: string) => {
todoStore.setState(state => ({
todos: [...state.todos, { id: Date.now(), text, completed: false }]
}));
};
// Toggle todo
const toggleTodo = (id: number) => {
todoStore.setState(state => ({
todos: state.todos.map(todo =>
todo.id === id ? { ...todo, completed: !todo.completed } : todo
)
}));
};
// Remove todo
const removeTodo = (id: number) => {
todoStore.setState(state => ({
todos: state.todos.filter(todo => todo.id !== id)
}));
};React Todo Component
import { useStore } from 'controllex/react';
function TodoList() {
const todos = useStore(todoStore, state => state.todos);
return (
<ul>
{todos.map(todo => (
<li key={todo.id}>
<input
type="checkbox"
checked={todo.completed}
onChange={() => toggleTodo(todo.id)}
/>
<span style={{ textDecoration: todo.completed ? 'line-through' : 'none' }}>
{todo.text}
</span>
<button onClick={() => removeTodo(todo.id)}>Delete</button>
</li>
))}
</ul>
);
}API Reference
See API_CONTRACT.md for the complete API reference.
Core
| Function | Description |
|----------|-------------|
| createStore(config) | Creates a new state store |
| createSlice(config) | Creates a slice with auto-generated actions |
Store Methods
| Method | Description |
|--------|-------------|
| store.getState() | Returns current state |
| store.setState(partial \| updater) | Updates state |
| store.subscribe(listener) | Subscribes to changes |
React Hooks
| Hook | Description |
|------|-------------|
| useStore(store, selector?) | Subscribe to store with optional selector |
| createStoreHook(store) | Create a typed hook for a store |
| useStoreDispatch(store) | Get the setState function |
Plugins
| Function | Description |
|----------|-------------|
| persist(store, config) | Add persistence to a store |
| clearPersistedState(key) | Clear persisted state |
Contributing
We welcome contributions! See CONTRIBUTING.md for guidelines.
License
MIT © Plinio Mabesi
