JavaScript Architecture

JavaScript State Management: Redux, Zustand, and Modern Patterns

Master state management in JavaScript applications. Learn Redux, Zustand, Context API, and state management patterns for scalable applications.

By JavaScript Document Team
state-managementreduxzustandcontext-apifluxarchitecture

State management is crucial for building scalable JavaScript applications. As applications grow in complexity, managing state becomes challenging. This guide covers various state management approaches, from simple local state to complex global state management solutions.

Fundamentals of State Management

Understanding State Types

// Different Types of State in Applications
class StateTypes {
  // 1. Local Component State
  static createLocalState() {
    return {
      // UI state - form inputs, toggles, local loading states
      uiState: {
        isModalOpen: false,
        currentTab: 'general',
        formData: {
          name: '',
          email: '',
          message: '',
        },
      },

      // Derived state - computed from other state
      getDerivedState() {
        return {
          isFormValid:
            this.uiState.formData.name &&
            this.uiState.formData.email &&
            this.uiState.formData.message,
          characterCount: this.uiState.formData.message.length,
        };
      },
    };
  }

  // 2. Shared Component State
  static createSharedState() {
    return {
      // State shared between sibling components
      sharedUI: {
        selectedItems: [],
        filters: {
          category: 'all',
          sortBy: 'name',
          sortOrder: 'asc',
        },
      },
    };
  }

  // 3. Global Application State
  static createGlobalState() {
    return {
      // User authentication state
      auth: {
        user: null,
        isAuthenticated: false,
        permissions: [],
        token: null,
      },

      // Application data
      data: {
        users: [],
        posts: [],
        comments: [],
        cache: new Map(),
      },

      // Global UI state
      ui: {
        theme: 'light',
        language: 'en',
        notifications: [],
        loading: false,
        error: null,
      },
    };
  }

  // 4. Server State (Remote Data)
  static createServerState() {
    return {
      // Cached server data
      entities: {
        users: {
          byId: {},
          allIds: [],
          loading: false,
          error: null,
          lastFetch: null,
        },
        posts: {
          byId: {},
          allIds: [],
          loading: false,
          error: null,
          lastFetch: null,
        },
      },

      // Query metadata
      queries: {
        'users/all': {
          data: [],
          status: 'idle', // idle, loading, success, error
          error: null,
          lastFetch: null,
          refetchOnMount: true,
        },
      },
    };
  }
}

// State Management Principles
class StateManagementPrinciples {
  // Single Source of Truth
  static singleSourceOfTruth = {
    // Bad: Multiple sources of truth
    badExample: {
      userInComponent: { id: 1, name: 'John' },
      userInLocalStorage: '{"id": 1, "name": "Johnny"}',
      userInGlobalState: { id: 1, name: 'Jon' },
    },

    // Good: Single source of truth
    goodExample: {
      globalState: {
        entities: {
          users: {
            1: { id: 1, name: 'John' },
          },
        },
      },
    },
  };

  // State is Read-Only
  static immutableUpdates = {
    // Bad: Direct mutation
    badUpdate(state, action) {
      state.count++; // Mutates state directly
      state.items.push(action.payload); // Mutates array
      return state;
    },

    // Good: Immutable updates
    goodUpdate(state, action) {
      return {
        ...state,
        count: state.count + 1,
        items: [...state.items, action.payload],
      };
    },
  };

  // Pure Functions for State Changes
  static pureReducers = {
    // Reducer function - pure, predictable
    counterReducer(state = { count: 0 }, action) {
      switch (action.type) {
        case 'INCREMENT':
          return { ...state, count: state.count + 1 };
        case 'DECREMENT':
          return { ...state, count: state.count - 1 };
        case 'SET_COUNT':
          return { ...state, count: action.payload };
        default:
          return state;
      }
    },

    // Complex state updates
    todosReducer(state = { items: [], filter: 'all' }, action) {
      switch (action.type) {
        case 'ADD_TODO':
          return {
            ...state,
            items: [
              ...state.items,
              {
                id: Date.now(),
                text: action.payload,
                completed: false,
                createdAt: new Date().toISOString(),
              },
            ],
          };

        case 'TOGGLE_TODO':
          return {
            ...state,
            items: state.items.map((item) =>
              item.id === action.payload
                ? { ...item, completed: !item.completed }
                : item
            ),
          };

        case 'SET_FILTER':
          return {
            ...state,
            filter: action.payload,
          };

        default:
          return state;
      }
    },
  };
}

Redux - Predictable State Container

Core Redux Implementation

// Redux Store Implementation
class ReduxStore {
  constructor(reducer, initialState = {}, middleware = []) {
    this.reducer = reducer;
    this.state = initialState;
    this.listeners = [];
    this.middleware = middleware;
    this.isDispatching = false;
  }

  getState() {
    if (this.isDispatching) {
      throw new Error(
        'You may not call store.getState() while the reducer is executing.'
      );
    }
    return this.state;
  }

  dispatch(action) {
    if (this.isDispatching) {
      throw new Error('Reducers may not dispatch actions.');
    }

    try {
      this.isDispatching = true;

      // Apply middleware
      let dispatch = this.dispatch.bind(this);
      let getState = this.getState.bind(this);

      const middlewareAPI = { dispatch, getState };
      const chain = this.middleware.map((middleware) =>
        middleware(middlewareAPI)
      );
      dispatch = chain.reduceRight(
        (composed, middleware) => middleware(composed),
        this._dispatch.bind(this)
      );

      return dispatch(action);
    } finally {
      this.isDispatching = false;
    }
  }

  _dispatch(action) {
    if (typeof action !== 'object' || action === null) {
      throw new Error('Actions must be plain objects.');
    }

    if (typeof action.type === 'undefined') {
      throw new Error('Actions may not have an undefined "type" property.');
    }

    this.state = this.reducer(this.state, action);
    this.listeners.forEach((listener) => listener());

    return action;
  }

  subscribe(listener) {
    if (typeof listener !== 'function') {
      throw new Error('Expected listener to be a function.');
    }

    this.listeners.push(listener);

    return () => {
      const index = this.listeners.indexOf(listener);
      this.listeners.splice(index, 1);
    };
  }
}

// Action Creators
class ActionCreators {
  // Synchronous action creators
  static increment() {
    return { type: 'INCREMENT' };
  }

  static decrement() {
    return { type: 'DECREMENT' };
  }

  static setCount(count) {
    return { type: 'SET_COUNT', payload: count };
  }

  static addTodo(text) {
    return { type: 'ADD_TODO', payload: text };
  }

  static toggleTodo(id) {
    return { type: 'TOGGLE_TODO', payload: id };
  }

  // Async action creators (thunks)
  static fetchUser(userId) {
    return async (dispatch, getState) => {
      dispatch({ type: 'FETCH_USER_START' });

      try {
        const response = await fetch(`/api/users/${userId}`);
        const user = await response.json();

        dispatch({
          type: 'FETCH_USER_SUCCESS',
          payload: user,
        });
      } catch (error) {
        dispatch({
          type: 'FETCH_USER_ERROR',
          payload: error.message,
        });
      }
    };
  }

  static updateUser(userId, updates) {
    return async (dispatch, getState) => {
      const state = getState();
      const currentUser = state.users.byId[userId];

      // Optimistic update
      dispatch({
        type: 'UPDATE_USER_OPTIMISTIC',
        payload: { id: userId, updates },
      });

      try {
        const response = await fetch(`/api/users/${userId}`, {
          method: 'PUT',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ ...currentUser, ...updates }),
        });

        const updatedUser = await response.json();

        dispatch({
          type: 'UPDATE_USER_SUCCESS',
          payload: updatedUser,
        });
      } catch (error) {
        // Revert optimistic update
        dispatch({
          type: 'UPDATE_USER_ERROR',
          payload: {
            id: userId,
            error: error.message,
            previousData: currentUser,
          },
        });
      }
    };
  }
}

// Complex Reducers with Normalization
class ComplexReducers {
  // Root reducer combining multiple reducers
  static rootReducer(state = {}, action) {
    return {
      auth: this.authReducer(state.auth, action),
      entities: this.entitiesReducer(state.entities, action),
      ui: this.uiReducer(state.ui, action),
    };
  }

  // Authentication reducer
  static authReducer(
    state = {
      user: null,
      isAuthenticated: false,
      loading: false,
      error: null,
    },
    action
  ) {
    switch (action.type) {
      case 'LOGIN_START':
        return {
          ...state,
          loading: true,
          error: null,
        };

      case 'LOGIN_SUCCESS':
        return {
          ...state,
          loading: false,
          user: action.payload,
          isAuthenticated: true,
          error: null,
        };

      case 'LOGIN_ERROR':
        return {
          ...state,
          loading: false,
          error: action.payload,
          isAuthenticated: false,
        };

      case 'LOGOUT':
        return {
          user: null,
          isAuthenticated: false,
          loading: false,
          error: null,
        };

      default:
        return state;
    }
  }

  // Normalized entities reducer
  static entitiesReducer(
    state = {
      users: { byId: {}, allIds: [] },
      posts: { byId: {}, allIds: [] },
    },
    action
  ) {
    switch (action.type) {
      case 'FETCH_USERS_SUCCESS':
        const users = action.payload;
        return {
          ...state,
          users: {
            byId: users.reduce(
              (acc, user) => ({
                ...acc,
                [user.id]: user,
              }),
              {}
            ),
            allIds: users.map((user) => user.id),
          },
        };

      case 'UPDATE_USER_SUCCESS':
        return {
          ...state,
          users: {
            ...state.users,
            byId: {
              ...state.users.byId,
              [action.payload.id]: action.payload,
            },
          },
        };

      case 'DELETE_USER_SUCCESS':
        const { [action.payload]: deleted, ...remainingUsers } =
          state.users.byId;
        return {
          ...state,
          users: {
            byId: remainingUsers,
            allIds: state.users.allIds.filter((id) => id !== action.payload),
          },
        };

      default:
        return state;
    }
  }

  // UI state reducer
  static uiReducer(
    state = {
      theme: 'light',
      sidebarOpen: false,
      notifications: [],
      modal: { isOpen: false, content: null },
    },
    action
  ) {
    switch (action.type) {
      case 'TOGGLE_THEME':
        return {
          ...state,
          theme: state.theme === 'light' ? 'dark' : 'light',
        };

      case 'TOGGLE_SIDEBAR':
        return {
          ...state,
          sidebarOpen: !state.sidebarOpen,
        };

      case 'ADD_NOTIFICATION':
        return {
          ...state,
          notifications: [
            ...state.notifications,
            {
              id: Date.now(),
              ...action.payload,
              timestamp: new Date().toISOString(),
            },
          ],
        };

      case 'REMOVE_NOTIFICATION':
        return {
          ...state,
          notifications: state.notifications.filter(
            (notification) => notification.id !== action.payload
          ),
        };

      default:
        return state;
    }
  }
}

// Redux Middleware
class ReduxMiddleware {
  // Logger middleware
  static logger(store) {
    return (next) => (action) => {
      console.group(`Action: ${action.type}`);
      console.log('Previous State:', store.getState());
      console.log('Action:', action);

      const result = next(action);

      console.log('Next State:', store.getState());
      console.groupEnd();

      return result;
    };
  }

  // Thunk middleware for async actions
  static thunk(store) {
    return (next) => (action) => {
      if (typeof action === 'function') {
        return action(store.dispatch, store.getState);
      }

      return next(action);
    };
  }

  // Error handling middleware
  static errorHandler(store) {
    return (next) => (action) => {
      try {
        return next(action);
      } catch (error) {
        console.error('Redux Error:', error);

        // Dispatch error action
        store.dispatch({
          type: 'GLOBAL_ERROR',
          payload: {
            message: error.message,
            stack: error.stack,
            action,
          },
        });

        throw error;
      }
    };
  }

  // API middleware
  static api(store) {
    return (next) => (action) => {
      if (!action.meta || !action.meta.api) {
        return next(action);
      }

      const { url, method = 'GET', data } = action.meta.api;
      const { type } = action;

      // Dispatch loading action
      store.dispatch({ type: `${type}_START` });

      return fetch(url, {
        method,
        headers: { 'Content-Type': 'application/json' },
        body: data ? JSON.stringify(data) : undefined,
      })
        .then((response) => response.json())
        .then((result) => {
          store.dispatch({
            type: `${type}_SUCCESS`,
            payload: result,
          });
          return result;
        })
        .catch((error) => {
          store.dispatch({
            type: `${type}_ERROR`,
            payload: error.message,
          });
          throw error;
        });
    };
  }
}

// Selectors for efficient state access
class Selectors {
  // Basic selectors
  static getAuth = (state) => state.auth;
  static getUser = (state) => state.auth.user;
  static isAuthenticated = (state) => state.auth.isAuthenticated;

  // Entity selectors
  static getUsers = (state) => state.entities.users.byId;
  static getUserById = (state, userId) => state.entities.users.byId[userId];
  static getAllUsers = (state) => {
    const { byId, allIds } = state.entities.users;
    return allIds.map((id) => byId[id]);
  };

  // Memoized selectors (reselect pattern)
  static createMemoizedSelector(dependencies, resultFunc) {
    let lastArgs = null;
    let lastResult = null;

    return (state) => {
      const args = dependencies.map((dep) => dep(state));

      if (lastArgs === null || !this.areArgsEqual(args, lastArgs)) {
        lastArgs = args;
        lastResult = resultFunc(...args);
      }

      return lastResult;
    };
  }

  static areArgsEqual(args1, args2) {
    if (args1.length !== args2.length) return false;

    for (let i = 0; i < args1.length; i++) {
      if (args1[i] !== args2[i]) return false;
    }

    return true;
  }

  // Computed selectors
  static getActiveUsers = this.createMemoizedSelector(
    [this.getAllUsers],
    (users) => users.filter((user) => user.active)
  );

  static getUsersByRole = this.createMemoizedSelector(
    [this.getAllUsers],
    (users) => {
      return users.reduce((acc, user) => {
        if (!acc[user.role]) acc[user.role] = [];
        acc[user.role].push(user);
        return acc;
      }, {});
    }
  );
}

// Usage Example
const store = new ReduxStore(
  ComplexReducers.rootReducer,
  {
    auth: { user: null, isAuthenticated: false, loading: false, error: null },
    entities: {
      users: { byId: {}, allIds: [] },
      posts: { byId: {}, allIds: [] },
    },
    ui: {
      theme: 'light',
      sidebarOpen: false,
      notifications: [],
      modal: { isOpen: false, content: null },
    },
  },
  [
    ReduxMiddleware.errorHandler,
    ReduxMiddleware.logger,
    ReduxMiddleware.thunk,
    ReduxMiddleware.api,
  ]
);

// Subscribe to store changes
const unsubscribe = store.subscribe(() => {
  const state = store.getState();
  console.log('State updated:', state);
});

// Dispatch actions
store.dispatch(ActionCreators.increment());
store.dispatch(ActionCreators.addTodo('Learn Redux'));
store.dispatch(ActionCreators.fetchUser(1));

Zustand - Simple State Management

Zustand Implementation

// Zustand-like implementation
class ZustandStore {
  constructor(createState) {
    this.state = {};
    this.listeners = new Set();
    this.version = 0;

    const setState = (partial, replace = false) => {
      this.version++;

      const nextState =
        typeof partial === 'function' ? partial(this.state) : partial;

      this.state = replace ? nextState : { ...this.state, ...nextState };

      this.listeners.forEach((listener) => listener(this.state, this.state));
    };

    const getState = () => this.state;

    const subscribe = (listener) => {
      this.listeners.add(listener);
      return () => this.listeners.delete(listener);
    };

    const destroy = () => {
      this.listeners.clear();
    };

    this.state = createState(setState, getState, {
      setState,
      getState,
      subscribe,
      destroy,
    });
  }

  getState() {
    return this.state;
  }

  setState(partial, replace = false) {
    this.version++;

    const nextState =
      typeof partial === 'function' ? partial(this.state) : partial;

    this.state = replace ? nextState : { ...this.state, ...nextState };

    this.listeners.forEach((listener) => listener(this.state, this.state));
  }

  subscribe(listener) {
    this.listeners.add(listener);
    return () => this.listeners.delete(listener);
  }

  destroy() {
    this.listeners.clear();
  }
}

// Create Zustand store
function createStore(createState) {
  return new ZustandStore(createState);
}

// Store Examples
class ZustandExamples {
  // Simple counter store
  static counterStore = createStore((set, get) => ({
    count: 0,
    increment: () => set((state) => ({ count: state.count + 1 })),
    decrement: () => set((state) => ({ count: state.count - 1 })),
    reset: () => set({ count: 0 }),
    incrementBy: (amount) => set((state) => ({ count: state.count + amount })),
  }));

  // Todo store with complex operations
  static todoStore = createStore((set, get) => ({
    todos: [],
    filter: 'all',

    addTodo: (text) =>
      set((state) => ({
        todos: [
          ...state.todos,
          {
            id: Date.now(),
            text,
            completed: false,
            createdAt: new Date().toISOString(),
          },
        ],
      })),

    toggleTodo: (id) =>
      set((state) => ({
        todos: state.todos.map((todo) =>
          todo.id === id ? { ...todo, completed: !todo.completed } : todo
        ),
      })),

    deleteTodo: (id) =>
      set((state) => ({
        todos: state.todos.filter((todo) => todo.id !== id),
      })),

    updateTodo: (id, updates) =>
      set((state) => ({
        todos: state.todos.map((todo) =>
          todo.id === id ? { ...todo, ...updates } : todo
        ),
      })),

    setFilter: (filter) => set({ filter }),

    clearCompleted: () =>
      set((state) => ({
        todos: state.todos.filter((todo) => !todo.completed),
      })),

    // Computed values
    get filteredTodos() {
      const { todos, filter } = get();
      switch (filter) {
        case 'active':
          return todos.filter((todo) => !todo.completed);
        case 'completed':
          return todos.filter((todo) => todo.completed);
        default:
          return todos;
      }
    },

    get stats() {
      const todos = get().todos;
      return {
        total: todos.length,
        completed: todos.filter((todo) => todo.completed).length,
        active: todos.filter((todo) => !todo.completed).length,
      };
    },
  }));

  // User management store with API integration
  static userStore = createStore((set, get) => ({
    users: [],
    currentUser: null,
    loading: false,
    error: null,

    setLoading: (loading) => set({ loading }),
    setError: (error) => set({ error }),

    fetchUsers: async () => {
      set({ loading: true, error: null });

      try {
        const response = await fetch('/api/users');
        const users = await response.json();
        set({ users, loading: false });
      } catch (error) {
        set({ error: error.message, loading: false });
      }
    },

    createUser: async (userData) => {
      set({ loading: true, error: null });

      try {
        const response = await fetch('/api/users', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify(userData),
        });

        const newUser = await response.json();

        set((state) => ({
          users: [...state.users, newUser],
          loading: false,
        }));

        return newUser;
      } catch (error) {
        set({ error: error.message, loading: false });
        throw error;
      }
    },

    updateUser: async (id, updates) => {
      const { users } = get();
      const userIndex = users.findIndex((user) => user.id === id);

      if (userIndex === -1) {
        throw new Error('User not found');
      }

      // Optimistic update
      const updatedUsers = [...users];
      updatedUsers[userIndex] = { ...updatedUsers[userIndex], ...updates };
      set({ users: updatedUsers });

      try {
        const response = await fetch(`/api/users/${id}`, {
          method: 'PUT',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify(updates),
        });

        const updatedUser = await response.json();

        set((state) => ({
          users: state.users.map((user) =>
            user.id === id ? updatedUser : user
          ),
        }));

        return updatedUser;
      } catch (error) {
        // Revert optimistic update
        set({ users });
        set({ error: error.message });
        throw error;
      }
    },

    deleteUser: async (id) => {
      const { users } = get();

      // Optimistic update
      set({ users: users.filter((user) => user.id !== id) });

      try {
        await fetch(`/api/users/${id}`, { method: 'DELETE' });
      } catch (error) {
        // Revert optimistic update
        set({ users });
        set({ error: error.message });
        throw error;
      }
    },

    setCurrentUser: (user) => set({ currentUser: user }),

    logout: () => set({ currentUser: null }),
  }));

  // Theme and UI store
  static uiStore = createStore((set, get) => ({
    theme: 'light',
    sidebarOpen: false,
    language: 'en',
    notifications: [],

    toggleTheme: () =>
      set((state) => ({
        theme: state.theme === 'light' ? 'dark' : 'light',
      })),

    setTheme: (theme) => set({ theme }),

    toggleSidebar: () =>
      set((state) => ({
        sidebarOpen: !state.sidebarOpen,
      })),

    setSidebarOpen: (open) => set({ sidebarOpen: open }),

    setLanguage: (language) => set({ language }),

    addNotification: (notification) =>
      set((state) => ({
        notifications: [
          ...state.notifications,
          {
            id: Date.now(),
            timestamp: new Date().toISOString(),
            ...notification,
          },
        ],
      })),

    removeNotification: (id) =>
      set((state) => ({
        notifications: state.notifications.filter((n) => n.id !== id),
      })),

    clearNotifications: () => set({ notifications: [] }),

    // Auto-remove notifications after timeout
    addTimedNotification: (notification, timeout = 5000) => {
      const id = Date.now();

      set((state) => ({
        notifications: [
          ...state.notifications,
          { id, timestamp: new Date().toISOString(), ...notification },
        ],
      }));

      setTimeout(() => {
        set((state) => ({
          notifications: state.notifications.filter((n) => n.id !== id),
        }));
      }, timeout);

      return id;
    },
  }));
}

// Store Composition and Middleware
class ZustandMiddleware {
  // Persistence middleware
  static persist(config, options = {}) {
    const {
      name,
      storage = localStorage,
      serialize = JSON.stringify,
      deserialize = JSON.parse,
      partialize = (state) => state,
    } = options;

    return (set, get, api) => {
      const initialState = config(
        (...args) => {
          set(...args);
          const state = partialize(get());
          storage.setItem(name, serialize(state));
        },
        get,
        api
      );

      // Load persisted state
      try {
        const persistedState = storage.getItem(name);
        if (persistedState) {
          const parsed = deserialize(persistedState);
          return { ...initialState, ...parsed };
        }
      } catch (error) {
        console.error('Failed to load persisted state:', error);
      }

      return initialState;
    };
  }

  // Logger middleware
  static logger(config, options = {}) {
    const { name = 'store' } = options;

    return (set, get, api) => {
      const loggedSet = (...args) => {
        const prevState = get();
        set(...args);
        const nextState = get();

        console.group(`${name} state change`);
        console.log('Previous state:', prevState);
        console.log('Arguments:', args);
        console.log('Next state:', nextState);
        console.groupEnd();
      };

      return config(loggedSet, get, api);
    };
  }

  // DevTools middleware
  static devtools(config, options = {}) {
    const { name = 'store', serialize = true } = options;

    return (set, get, api) => {
      let isRecording = true;

      const devtoolsSet = (...args) => {
        if (isRecording && window.__REDUX_DEVTOOLS_EXTENSION__) {
          const prevState = get();
          set(...args);
          const nextState = get();

          window.__REDUX_DEVTOOLS_EXTENSION__.send(
            {
              type: 'setState',
              args: serialize ? JSON.stringify(args) : args,
            },
            nextState
          );
        } else {
          set(...args);
        }
      };

      const result = config(devtoolsSet, get, api);

      if (window.__REDUX_DEVTOOLS_EXTENSION__) {
        window.__REDUX_DEVTOOLS_EXTENSION__.init(result);
      }

      return result;
    };
  }
}

// Usage examples
const persistedTodoStore = createStore(
  ZustandMiddleware.logger(
    ZustandMiddleware.persist(ZustandExamples.todoStore._createState, {
      name: 'todo-storage',
      partialize: (state) => ({ todos: state.todos, filter: state.filter }),
    }),
    { name: 'Todo Store' }
  )
);

// Subscribe to store changes
const unsubscribeTodos = ZustandExamples.todoStore.subscribe((state) => {
  console.log('Todo state changed:', state);
});

const unsubscribeUI = ZustandExamples.uiStore.subscribe((state) => {
  console.log('UI state changed:', state);
});

// Use the stores
ZustandExamples.todoStore.getState().addTodo('Learn Zustand');
ZustandExamples.todoStore.getState().addTodo('Build an app');

ZustandExamples.uiStore.getState().toggleTheme();
ZustandExamples.uiStore.getState().addTimedNotification({
  type: 'success',
  message: 'Todo added successfully!',
});

console.log('Todo stats:', ZustandExamples.todoStore.getState().stats);
console.log(
  'Filtered todos:',
  ZustandExamples.todoStore.getState().filteredTodos
);

Context API and React State

Context API Implementation

// Context API for React-like applications
class ContextAPI {
  constructor() {
    this.contexts = new Map();
  }

  // Create a new context
  createContext(defaultValue) {
    const contextId = Symbol('context');
    const context = {
      id: contextId,
      defaultValue,
      providers: new Map(),
      consumers: new Set(),
    };

    this.contexts.set(contextId, context);

    return {
      Provider: this.createProvider(context),
      Consumer: this.createConsumer(context),
      id: contextId,
    };
  }

  createProvider(context) {
    return class Provider {
      constructor(value, children = []) {
        this.value = value;
        this.children = children;
        this.id = Symbol('provider');

        context.providers.set(this.id, this);
      }

      updateValue(newValue) {
        this.value = newValue;
        // Notify all consumers
        context.consumers.forEach((consumer) => {
          if (consumer.providerId === this.id) {
            consumer.onUpdate(newValue);
          }
        });
      }

      destroy() {
        context.providers.delete(this.id);
      }
    };
  }

  createConsumer(context) {
    return class Consumer {
      constructor(onUpdate, providerId = null) {
        this.onUpdate = onUpdate;
        this.providerId = providerId;
        this.id = Symbol('consumer');

        context.consumers.add(this);
      }

      getValue() {
        if (this.providerId) {
          const provider = context.providers.get(this.providerId);
          return provider ? provider.value : context.defaultValue;
        }

        // Find nearest provider
        const providers = Array.from(context.providers.values());
        return providers.length > 0 ? providers[0].value : context.defaultValue;
      }

      destroy() {
        context.consumers.delete(this);
      }
    };
  }
}

// State Management with Context Pattern
class StateContextManager {
  // Auth Context
  static createAuthContext() {
    const authContext = new ContextAPI().createContext({
      user: null,
      isAuthenticated: false,
      login: () => {},
      logout: () => {},
      loading: false,
      error: null,
    });

    class AuthProvider extends authContext.Provider {
      constructor() {
        super({
          user: null,
          isAuthenticated: false,
          loading: false,
          error: null,
          login: this.login.bind(this),
          logout: this.logout.bind(this),
          register: this.register.bind(this),
          resetPassword: this.resetPassword.bind(this),
        });

        this.loadUserFromStorage();
      }

      loadUserFromStorage() {
        try {
          const token = localStorage.getItem('authToken');
          const user = localStorage.getItem('user');

          if (token && user) {
            this.updateValue({
              ...this.value,
              user: JSON.parse(user),
              isAuthenticated: true,
            });
          }
        } catch (error) {
          console.error('Failed to load user from storage:', error);
        }
      }

      async login(email, password) {
        this.updateValue({ ...this.value, loading: true, error: null });

        try {
          const response = await fetch('/api/auth/login', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ email, password }),
          });

          if (!response.ok) {
            throw new Error('Login failed');
          }

          const { user, token } = await response.json();

          localStorage.setItem('authToken', token);
          localStorage.setItem('user', JSON.stringify(user));

          this.updateValue({
            ...this.value,
            user,
            isAuthenticated: true,
            loading: false,
            error: null,
          });

          return user;
        } catch (error) {
          this.updateValue({
            ...this.value,
            loading: false,
            error: error.message,
          });
          throw error;
        }
      }

      async logout() {
        try {
          await fetch('/api/auth/logout', { method: 'POST' });
        } catch (error) {
          console.error('Logout error:', error);
        } finally {
          localStorage.removeItem('authToken');
          localStorage.removeItem('user');

          this.updateValue({
            user: null,
            isAuthenticated: false,
            loading: false,
            error: null,
            login: this.login.bind(this),
            logout: this.logout.bind(this),
            register: this.register.bind(this),
            resetPassword: this.resetPassword.bind(this),
          });
        }
      }

      async register(userData) {
        this.updateValue({ ...this.value, loading: true, error: null });

        try {
          const response = await fetch('/api/auth/register', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify(userData),
          });

          if (!response.ok) {
            throw new Error('Registration failed');
          }

          const { user, token } = await response.json();

          localStorage.setItem('authToken', token);
          localStorage.setItem('user', JSON.stringify(user));

          this.updateValue({
            ...this.value,
            user,
            isAuthenticated: true,
            loading: false,
            error: null,
          });

          return user;
        } catch (error) {
          this.updateValue({
            ...this.value,
            loading: false,
            error: error.message,
          });
          throw error;
        }
      }

      async resetPassword(email) {
        this.updateValue({ ...this.value, loading: true, error: null });

        try {
          await fetch('/api/auth/reset-password', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ email }),
          });

          this.updateValue({
            ...this.value,
            loading: false,
            error: null,
          });
        } catch (error) {
          this.updateValue({
            ...this.value,
            loading: false,
            error: error.message,
          });
          throw error;
        }
      }
    }

    return { AuthProvider, AuthConsumer: authContext.Consumer };
  }

  // Theme Context
  static createThemeContext() {
    const themeContext = new ContextAPI().createContext({
      theme: 'light',
      toggleTheme: () => {},
      setTheme: () => {},
      colors: {},
      spacing: {},
    });

    class ThemeProvider extends themeContext.Provider {
      constructor() {
        const themes = {
          light: {
            colors: {
              primary: '#007bff',
              secondary: '#6c757d',
              background: '#ffffff',
              text: '#212529',
              border: '#dee2e6',
            },
            spacing: {
              xs: '0.25rem',
              sm: '0.5rem',
              md: '1rem',
              lg: '1.5rem',
              xl: '3rem',
            },
          },
          dark: {
            colors: {
              primary: '#4dabf7',
              secondary: '#adb5bd',
              background: '#121212',
              text: '#ffffff',
              border: '#495057',
            },
            spacing: {
              xs: '0.25rem',
              sm: '0.5rem',
              md: '1rem',
              lg: '1.5rem',
              xl: '3rem',
            },
          },
        };

        const savedTheme = localStorage.getItem('theme') || 'light';

        super({
          theme: savedTheme,
          themes,
          toggleTheme: this.toggleTheme.bind(this),
          setTheme: this.setTheme.bind(this),
          ...themes[savedTheme],
        });
      }

      toggleTheme() {
        const newTheme = this.value.theme === 'light' ? 'dark' : 'light';
        this.setTheme(newTheme);
      }

      setTheme(theme) {
        localStorage.setItem('theme', theme);

        this.updateValue({
          ...this.value,
          theme,
          ...this.value.themes[theme],
        });

        // Apply theme to document
        document.documentElement.setAttribute('data-theme', theme);
      }
    }

    return { ThemeProvider, ThemeConsumer: themeContext.Consumer };
  }
}

// Usage examples
const { AuthProvider, AuthConsumer } = StateContextManager.createAuthContext();
const { ThemeProvider, ThemeConsumer } =
  StateContextManager.createThemeContext();

// Create providers
const authProvider = new AuthProvider();
const themeProvider = new ThemeProvider();

// Create consumers
const authConsumer = new AuthConsumer((authState) => {
  console.log('Auth state changed:', authState);
});

const themeConsumer = new ThemeConsumer((themeState) => {
  console.log('Theme state changed:', themeState);
  // Apply theme changes to UI
  document.body.style.backgroundColor = themeState.colors.background;
  document.body.style.color = themeState.colors.text;
});

// Use the context
console.log('Current auth state:', authConsumer.getValue());
console.log('Current theme state:', themeConsumer.getValue());

// Perform actions
authProvider.value.login('user@example.com', 'password');
themeProvider.value.toggleTheme();

Conclusion

State management is a critical aspect of building scalable JavaScript applications. Choose the right approach based on your application's complexity: local state for simple scenarios, Context API for moderate complexity, and dedicated libraries like Redux or Zustand for complex applications with intricate state interactions. Remember to consider factors like predictability, debuggability, performance, and team familiarity when making your choice. Each approach has its strengths, and understanding multiple patterns will make you a more effective developer.