This page is under construction and constantly being updated, stay tuned!

State Management

Context API

Context API is a React feature that allows sharing data between components without having to pass props manually at every level of the component tree (prop drilling).

Example of creating a context and its provider:

import React, { createContext, useState, useContext } from 'react';

const ThemeContext = createContext();

export const ThemeProvider = ({ children }) => {
  const [isDarkMode, setIsDarkMode] = useState(false);

  const toggleTheme = () => {
    setIsDarkMode(prev => !prev);
  };

  const value = {
    isDarkMode,
    toggleTheme,
    theme: isDarkMode ? 'dark' : 'light'
  };

  return (
    <ThemeContext.Provider value={value}>
      {children}
    </ThemeContext.Provider>
  );
};

export const useTheme = () => {
  const context = useContext(ThemeContext);
  
  if (!context) {
    throw new Error('useTheme must be used within a ThemeProvider');
  }
  
  return context;
};

Redux

Redux is a JavaScript library for application state management. It works as a predictable state container that helps manage your application's global state in a consistent way.

Fundamental Principles:

  1. Single Source of Truth

    • All application state is stored in a single object called store
  2. State is Read-Only

    • State cannot be modified directly
    • Changes are made through actions
  3. Changes are Made with Pure Functions

    • Reducers are pure functions that specify how the state changes

Usage example:

// store.js
import { createStore } from 'redux';

// Actions
const ADD_TODO = 'ADD_TODO';
const TOGGLE_TODO = 'TOGGLE_TODO';

// Action Creators
export const addTodo = (text) => ({
  type: ADD_TODO,
  payload: { id: Date.now(), text, completed: false }
});

export const toggleTodo = (id) => ({
  type: TOGGLE_TODO,
  payload: id
});

// Reducer
const initialState = {
  todos: []
};

const todoReducer = (state = initialState, action) => {
  switch (action.type) {
    case ADD_TODO:
      return {
        ...state,
        todos: [...state.todos, action.payload]
      };
    
    case TOGGLE_TODO:
      return {
        ...state,
        todos: state.todos.map(todo =>
          todo.id === action.payload
            ? { ...todo, completed: !todo.completed }
            : todo
        )
      };
    
    default:
      return state;
  }
};

// Store
export const store = createStore(todoReducer);

// App.js
import React from 'react';
import { Provider } from 'react-redux';
import { store } from './store';
import TodoList from './components/TodoList';
import AddTodo from './components/AddTodo';

function App() {
  return (
    <Provider store={store}>
      <div className="App">
        <h1>Todo App with Redux</h1>
        <AddTodo />
        <TodoList />
      </div>
    </Provider>
  );
}

// components/AddTodo.js
import React, { useState } from 'react';
import { useDispatch } from 'react-redux';
import { addTodo } from '../store';

const AddTodo = () => {
  const [text, setText] = useState('');
  const dispatch = useDispatch();

  const handleSubmit = (e) => {
    e.preventDefault();
    if (text.trim()) {
      dispatch(addTodo(text));
      setText('');
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="text"
        value={text}
        onChange={(e) => setText(e.target.value)}
        placeholder="Add todo..."
      />
      <button type="submit">Add</button>
    </form>
  );
};
Comparison table between Redux and Context API
CharacteristicsReduxContext API
ComplexityMore boilerplateLess code
ToolingRedux DevToolsReact DevTools
PerformanceOptimizedPoorly used can cause re-renders
Use casesComplex applicationsSimple/medium applications
Learning curveHigherLower