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:
-
Single Source of Truth
- All application state is stored in a single object called store
-
State is Read-Only
- State cannot be modified directly
- Changes are made through actions
-
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>
);
};
| Characteristics | Redux | Context API |
|---|---|---|
| Complexity | More boilerplate | Less code |
| Tooling | Redux DevTools | React DevTools |
| Performance | Optimized | Poorly used can cause re-renders |
| Use cases | Complex applications | Simple/medium applications |
| Learning curve | Higher | Lower |