Context Utility
Description
The createContext utility provides a simple way to create global or named shared state that components can subscribe to. It enables reactive state management with automatic subscriber notifications on value changes.
Basic Usage
Import and create a context to manage shared state:
import createContext from './utils/context.js';
// Create a named context with initial value
const userContext = createContext('user', { name: 'Guest' });
// Subscribe to changes
userContext.subscribe((user) => {
console.log('User changed:', user);
});
// Update the context value
userContext.set({ name: 'John Doe' });
API Methods
createContext(name, initialValue)
Creates or retrieves a context with the specified name.
name: string (optional)
The name of the context. Defaults to 'global'. Using the same name returns the same context instance.
initialValue: any (optional)
The initial value for the context. Only set if the context doesn't already have a value.
Returns: Object
An object with the following methods:
get()
Returns the current value of the context.
const currentValue = userContext.get();
set(value)
Updates the context value and notifies all subscribers.
userContext.set({ name: 'Jane Doe', role: 'admin' });
subscribe(callback)
Subscribes to context changes. The callback is immediately invoked with the current value, then called again whenever the value changes.
callback: Function
Function to call when the context value changes. Receives the new value as an argument.
Returns: Function
An unsubscribe function to remove the subscription.
const unsubscribe = userContext.subscribe((value) => {
console.log('New value:', value);
});
// Later, stop listening
unsubscribe();
unsubscribe(callback)
Removes a subscriber callback from the context.
const handler = (value) => console.log(value);
userContext.subscribe(handler);
userContext.unsubscribe(handler);
Examples
Theme Management
import createContext from './utils/context.js';
const themeContext = createContext('theme', 'light');
// Components can subscribe to theme changes
themeContext.subscribe((theme) => {
document.body.className = theme;
});
// Toggle theme from anywhere
const toggleTheme = () => {
const current = themeContext.get();
themeContext.set(current === 'light' ? 'dark' : 'light');
};
Component State Sharing
import createContext from './utils/context.js';
const cartContext = createContext('cart', []);
// Add item from one component
const addToCart = (item) => {
const items = cartContext.get();
cartContext.set([...items, item]);
};
// Display cart in another component
cartContext.subscribe((items) => {
document.querySelector('.cart-count').textContent = items.length;
});
Global vs Named Contexts
import createContext from './utils/context.js';
// Use default global context
const globalCtx = createContext();
globalCtx.set({ appReady: true });
// Named contexts are isolated
const userCtx = createContext('user');
const settingsCtx = createContext('settings');
// Same name returns the same context instance
const userCtx2 = createContext('user');
console.log(userCtx === userCtx2); // true
Working Example
<div id="context-demo">
<p>Current count: <strong id="count-display">0</strong></p>
<button id="increment">Increment</button>
<button id="decrement">Decrement</button>
<button id="reset">Reset</button>
</div>
<script type="module">
import createContext from '../src/utils/context.js';
const counterContext = createContext('counter', 0);
// Subscribe to updates
counterContext.subscribe((count) => {
document.getElementById('count-display').textContent = count;
});
// Button handlers
document.getElementById('increment')
.addEventListener('click', () => {
counterContext.set(counterContext.get() + 1);
});
document.getElementById('decrement')
.addEventListener('click', () => {
counterContext.set(counterContext.get() - 1);
});
document.getElementById('reset')
.addEventListener('click', () => {
counterContext.set(0);
});
</script>
Current count: 0