anyState is a tiny, framework-agnostic state management library that works with any frontend framework!
- Simple Object-based API: State is just an observable object
- Path-based Updates: Update nested values using simple path notation
- Change Watching: Subscribe to state changes with callback functions
- Framework Independent: Works with React, Vue, Svelte, Solid, or any framework
- Tiny Bundle Size: Under 5KB minified
- TypeScript Support: Full TypeScript definitions included
Back to basics - anyState uses callback functions to handle state changes. Each change is identified by a unique path string to ensure precise state updates. This allows you to track any changes from anywhere in your application.
npm install anystateyarn add anystatepnpm add anystate- Initialize anyState
- Simple state management
- getItem/setItem with path notation
- Watch onChange functionality
- Vue-like multiple property watching
- TypeScript support
- React hooks integration
- Vue composables
- Svelte stores compatibility
- Persistence plugins
Import and initialize anyState with createStore():
import { createStore } from 'anystate';
const store = createStore({
user: {
name: 'John',
age: 30,
preferences: {
theme: 'dark'
}
},
todos: [
{ id: 1, text: 'Learn anyState', completed: false },
{ id: 2, text: 'Build awesome app', completed: false }
]
});const state = store.getState();
console.log(state); // Returns the entire state objectstore.setState({
user: {
name: 'Jane',
age: 25,
preferences: {
theme: 'light'
}
},
todos: []
});anyState supports dot notation and array indexing for nested operations:
// Update simple property
store.setItem('user.name', 'Alice');
// Update nested object property
store.setItem('user.preferences.theme', 'auto');
// Update array item
store.setItem('todos[0].completed', true);
// Update nested array property
store.setItem('todos[0].text', 'Learn anyState β');// Get simple property
const userName = store.getItem('user.name');
// Get nested object
const preferences = store.getItem('user.preferences');
// Get array item
const firstTodo = store.getItem('todos[0]');
// Get nested array property
const isCompleted = store.getItem('todos[0].completed');store.watch('user.name', (newValue, oldValue) => {
console.log(`User name changed from ${oldValue} to ${newValue}`);
});store.watch({
'user.name': (newValue, oldValue) => {
console.log(`Name: ${oldValue} β ${newValue}`);
},
'user.age': (newValue, oldValue) => {
console.log(`Age: ${oldValue} β ${newValue}`);
},
'todos[0].completed': (newValue, oldValue) => {
console.log(`First todo completed: ${newValue}`);
}
});// Watch entire user object
store.watch('user', (newUser, oldUser) => {
console.log('User object changed:', { newUser, oldUser });
});
// Watch array changes
store.watch('todos', (newTodos, oldTodos) => {
console.log(`Todo count: ${oldTodos?.length} β ${newTodos?.length}`);
});Creates a new anyState store instance.
Parameters:
initialState(Object): The initial state object
Returns: Store instance with the following methods:
Returns the entire current state.
Replaces the entire state with a new state object.
Parameters:
newState(Object): The new state object
Gets a value at the specified path.
Parameters:
path(string): Dot notation path (e.g., 'user.name', 'items[0].title')
Returns: The value at the specified path
Sets a value at the specified path.
Parameters:
path(string): Dot notation pathvalue(any): The value to set
Watches for changes at specified paths.
Parameters:
pathOrObject(string | Object): Path string or object with path-callback pairscallback(Function): Callback function for string paths(newValue, oldValue) => void
React hook for subscribing to store values.
Parameters:
store(Store): anyState store instancepath(string): Dot notation path to watch
Returns: [value, setValue] tuple similar to React's useState
React hook for subscribing to multiple store values.
Parameters:
store(Store): anyState store instancepaths(Object): Object mapping property names to paths
Returns: Object with values and setter functions
Vue composable for subscribing to store values.
Parameters:
store(Store): anyState store instancepath(string): Dot notation path to watch
Returns: [ref, setValue] tuple with reactive ref and setter function
Vue composable for subscribing to multiple store values.
Parameters:
store(Store): anyState store instancepaths(Object): Object mapping property names to paths
Returns: Reactive object with values and setter functions
Vue composable for creating computed properties from store values.
Parameters:
store(Store): anyState store instancepaths(Array): Array of paths to watchcomputeFn(Function): Function to compute derived value
Returns: Computed ref
Creates a Svelte writable store from an anyState path.
Parameters:
store(Store): anyState store instancepath(string): Dot notation path to watch
Returns: Svelte writable store with subscribe, set, update, and destroy methods
Creates multiple Svelte stores from anyState paths.
Parameters:
store(Store): anyState store instancepaths(Object): Object mapping store names to paths
Returns: Object with Svelte writable stores
Creates a Svelte derived store from multiple anyState paths.
Parameters:
store(Store): anyState store instancepaths(Array): Array of paths to watchderiveFn(Function): Function to derive the value
Returns: Svelte derived store
Creates a Svelte readable store from an anyState path.
Parameters:
store(Store): anyState store instancepath(string): Dot notation path to watch
Returns: Svelte readable store
Adds persistence capabilities to an anyState store.
Parameters:
store(Store): anyState store instanceoptions(Object): Persistence configurationplugins(Array): Array of persistence plugins (default: [localStoragePlugin()])paths(Array): Specific paths to persist (default: [] - all state)throttle(number): Save throttle in milliseconds (default: 1000)autoSave(boolean): Enable automatic saving on changes (default: true)
Returns: Object with save(), load(), clear(), and destroy() methods
Persists state to browser localStorage.
Persists state to browser sessionStorage.
Persists state to browser IndexedDB.
Creates a custom persistence plugin.
anyState now provides built-in React hooks for seamless integration:
A React hook that subscribes to a specific path in the store and returns a stateful value and a setter function.
import { createStore, useAnyState } from 'anystate';
const store = createStore({
user: { name: 'John', age: 30 },
todos: []
});
function UserComponent() {
const [name, setName] = useAnyState(store, 'user.name');
const [age, setAge] = useAnyState(store, 'user.age');
return (
<div>
<h2>{name} ({age} years old)</h2>
<button onClick={() => setAge(age + 1)}>
Birthday! π
</button>
</div>
);
}For watching multiple values at once:
function UserForm() {
const userData = useAnyStateMultiple(store, {
name: 'user.name',
age: 'user.age',
email: 'user.email'
});
return (
<form>
<input
value={userData.name}
onChange={(e) => userData.setName(e.target.value)}
/>
<input
value={userData.age}
onChange={(e) => userData.setAge(e.target.value)}
/>
<input
value={userData.email}
onChange={(e) => userData.setEmail(e.target.value)}
/>
</form>
);
}import { createStore, useAnyState } from 'anystate';
const store = createStore({ count: 0 });
function Counter() {
const [count, setCount] = useAnyState(store, 'count');
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>
Increment
</button>
</div>
);
}
// You can also use the hook with nested paths
function UserProfile() {
const [name, setName] = useAnyState(store, 'user.name');
const [age, setAge] = useAnyState(store, 'user.age');
return (
<div>
<input
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="Name"
/>
<input
type="number"
value={age}
onChange={(e) => setAge(parseInt(e.target.value))}
placeholder="Age"
/>
</div>
);
}anyState provides Vue 3 composables for seamless integration with Vue's reactivity system:
A Vue composable that creates a reactive ref for a store value.
<template>
<div>
<h2>{{ name }} ({{ age }} years old)</h2>
<button @click="birthday">Birthday! π</button>
</div>
</template>
<script setup>
import { createStore, useAnyStateVue } from 'anystate';
const store = createStore({
user: { name: 'John', age: 30 }
});
const [name, setName] = useAnyStateVue(store, 'user.name');
const [age, setAge] = useAnyStateVue(store, 'user.age');
const birthday = () => setAge(age.value + 1);
</script>For managing multiple store values:
<script setup>
import { useAnyStateMultipleVue } from 'anystate';
const userData = useAnyStateMultipleVue(store, {
name: 'user.name',
age: 'user.age',
email: 'user.email'
});
// Access values: userData.name.value, userData.age.value
// Set values: userData.setName('New Name'), userData.setAge(25)
</script>For computed values derived from store data:
<script setup>
import { useAnyStateComputed } from 'anystate';
const fullName = useAnyStateComputed(
store,
['user.firstName', 'user.lastName'],
(first, last) => `${first} ${last}`
);
// fullName.value will automatically update when firstName or lastName change
</script><template>
<div>
<p>Count: {{ count }}</p>
<button @click="increment">Increment</button>
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue';
import { createStore } from 'anystate';
const store = createStore({ count: 0 });
const count = ref(store.getItem('count'));
let unwatch;
onMounted(() => {
unwatch = store.watch('count', (newValue) => {
count.value = newValue;
});
});
onUnmounted(() => {
if (unwatch) unwatch();
});
const increment = () => {
store.setItem('count', store.getItem('count') + 1);
};
</script><template>
<div>
<p>Count: {{ count }}</p>
<button @click="increment">Increment</button>
</div>
</template>
<script setup>
import { createStore, useAnyStateVue } from 'anystate';
const store = createStore({ count: 0 });
const [count, setCount] = useAnyStateVue(store, 'count');
const increment = () => {
setCount(count.value + 1);
};
</script>anyState provides seamless integration with Svelte's store system:
Creates a Svelte writable store that stays in sync with anyState.
<script>
import { createStore, createAnyStateStore } from 'anystate';
const store = createStore({
user: { name: 'John', age: 30 }
});
const name = createAnyStateStore(store, 'user.name');
const age = createAnyStateStore(store, 'user.age');
function birthday() {
age.update(current => current + 1);
}
</script>
<div>
<h2>{$name} ({$age} years old)</h2>
<button on:click={birthday}>Birthday! π</button>
</div>For managing multiple stores:
<script>
import { createAnyStateStores } from 'anystate';
const { name, age, email } = createAnyStateStores(store, {
name: 'user.name',
age: 'user.age',
email: 'user.email'
});
</script>
<form>
<input bind:value={$name} placeholder="Name" />
<input bind:value={$age} type="number" placeholder="Age" />
<input bind:value={$email} type="email" placeholder="Email" />
</form>For computed/derived values:
<script>
import { createAnyStateDerived } from 'anystate';
const fullName = createAnyStateDerived(
store,
['user.firstName', 'user.lastName'],
(first, last) => `${first} ${last}`
);
</script>
<p>Welcome, {$fullName}!</p>For read-only stores:
<script>
import { createAnyStateReadable } from 'anystate';
const status = createAnyStateReadable(store, 'app.status');
</script>
<div class="status-{$status}">
Status: {$status}
</div>anyState provides flexible persistence plugins to save and restore state:
import { createStore, addPersistence, localStoragePlugin } from 'anystate';
const store = createStore({
user: { name: 'John', preferences: { theme: 'dark' } },
todos: []
});
// Add persistence
const persistence = await addPersistence(store, {
plugins: [localStoragePlugin('my-app-state')],
autoSave: true,
throttle: 1000
});
// Load existing state
await persistence.load();
// State changes are automatically saved to localStorage
store.setItem('user.name', 'Jane'); // Saved after 1 second// Use multiple storage plugins with fallback
const persistence = await addPersistence(store, {
plugins: [
indexedDBPlugin('myapp', 'state', 'appstate'),
localStoragePlugin('my-app-backup'),
sessionStoragePlugin('my-app-session')
]
});// Only persist specific paths
const persistence = await addPersistence(store, {
paths: ['user.preferences', 'todos'],
plugins: [localStoragePlugin('user-data')]
});// Create a custom plugin (e.g., for server storage)
const serverPlugin = createCustomPlugin(
'server',
async () => {
const response = await fetch('/api/state');
return response.json();
},
async (state) => {
await fetch('/api/state', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(state)
});
},
async () => {
await fetch('/api/state', { method: 'DELETE' });
}
);
const persistence = await addPersistence(store, {
plugins: [serverPlugin]
});// Disable auto-save for manual control
const persistence = await addPersistence(store, {
autoSave: false,
plugins: [localStoragePlugin()]
});
// Manual operations
await persistence.save(); // Save current state
await persistence.load(); // Load saved state
await persistence.clear(); // Clear saved state
persistence.destroy(); // Clean up watchersExplore complete working examples in different frameworks:
- React Todo App - Complete todo application with React
- Solid Todo App - Todo app built with SolidJS
- Svelte Todo App - Todo app using Svelte
Each example demonstrates:
- State initialization and management
- Path-based updates for nested data
- Change watching and UI reactivity
- Framework-specific integration patterns
- Interactive Examples & Playground - Coming Soon
- Video Tutorials - Coming Soon
- Advanced Patterns Guide - Coming Soon
# Install dependencies
npm install
# Run tests
npm test
# Development mode (TypeScript watch)
npm run dev
# Build for production
npm run buildβββ src/
β βββ index.ts # Main library code
β βββ type.d.ts # TypeScript definitions
βββ test/ # Test files
βββ examples/ # Framework examples
β βββ todo-react/ # React example
β βββ todo-solid/ # Solid example
β βββ todo-svelte/ # Svelte example
βββ dist/ # Built files
# React example
cd examples/todo-react && npm install && npm start
# Solid example
cd examples/todo-solid && npm install && npm start
# Svelte example
cd examples/todo-svelte && npm install && npm run dev- Fork the repository
- Create a feature branch:
git checkout -b feature-name - Make your changes and add tests
- Run tests:
npm test - Commit your changes:
git commit -am 'Add feature' - Push to the branch:
git push origin feature-name - Submit a pull request
MIT License - see LICENSE.md for details.