Context Utility

Table of Contents

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