Redux is an open-source JavaScript library for managing and centralizing application state. It provides a predictable state container, making it easier to manage complex application states, especially in large-scale applications with many components interacting with shared data. Redux ensures that state changes are transparent and debuggable, leading to more robust and maintainable codebases.
Core Principles:
1. Single Source of Truth: The entire application state is stored in a single plain JavaScript object tree within a single *store*. This centralized approach simplifies state management and debugging.
2. State is Read-only: The only way to change the state is to emit an *action*, which is a plain JavaScript object describing what happened. This immutability ensures that state changes are explicit and traceable.
3. Changes are Made with Pure Functions: To specify how the state tree is transformed by actions, you write pure functions called *reducers*. Reducers take the current state and an action, and return a *new* state, without mutating the original state or performing side effects.
Key Components of Redux:
* Store: The single source of truth that holds the application's state. It provides methods like `getState()`, `dispatch(action)`, and `subscribe(listener)`.
* Actions: Plain JavaScript objects that describe *what happened*. They must have a `type` property, indicating the type of action performed, and can carry additional data (payload). For example: `{ type: 'INCREMENT', payload: 1 }`.
* Reducers: Pure functions that take the current `state` and an `action` as arguments, and return a *new* state. They describe how the application's state changes in response to actions.
* Dispatch: A method provided by the store used to send (dispatch) an action. When an action is dispatched, Redux runs all the reducers with the current state and the action, and updates the store with the new state.
* Selectors: Functions used to extract specific pieces of data from the Redux store state. They help in optimizing performance by ensuring components only re-render when the specific data they depend on changes.
* Middleware: Provides a third-party extension point between dispatching an action and the moment it reaches the reducer. Common uses include logging, crash reporting, and performing asynchronous operations (e.g., fetching data from an API using `redux-thunk` or `redux-saga`).
Redux with React (using `react-redux`):
The `react-redux` library provides official React bindings for Redux.
* `Provider` Component: Wraps your root React component and makes the Redux store available to any nested components that need to access it.
* `useSelector` Hook: Allows functional components to extract data from the Redux store state. It takes a selector function as an argument, which receives the entire Redux state and returns the desired piece of data.
* `useDispatch` Hook: Returns a reference to the `dispatch` function from the Redux store. Components use this to dispatch actions and trigger state changes.
Redux Toolkit is the recommended way to write Redux logic today. It simplifies common Redux tasks, providing utilities like `configureStore` (for store setup) and `createSlice` (for defining reducers and actions in one place).
Example Code
// Install necessary packages:
// npm install @reduxjs/toolkit react-redux react
// or yarn add @reduxjs/toolkit react-redux react
// --- 1. src/app/store.js ---
import { configureStore } from '@reduxjs/toolkit';
import counterReducer from '../features/counter/counterSlice';
export const store = configureStore({
reducer: {
counter: counterReducer,
},
});
// --- 2. src/features/counter/counterSlice.js ---
import { createSlice } from '@reduxjs/toolkit';
const initialState = {
value: 0,
};
export const counterSlice = createSlice({
name: 'counter',
initialState,
reducers: {
increment: (state) => {
// Redux Toolkit allows us to write "mutating" logic in reducers;
// it doesn't actually mutate the state because it uses the Immer library,
// which detects changes to a "draft state" and produces a brand new
// immutable state based off those changes.
state.value += 1;
},
decrement: (state) => {
state.value -= 1;
},
incrementByAmount: (state, action) => {
state.value += action.payload;
},
},
});
// Action creators are generated for each case reducer function
export const { increment, decrement, incrementByAmount } = counterSlice.actions;
export default counterSlice.reducer;
// --- 3. src/features/counter/Counter.js ---
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { decrement, increment, incrementByAmount } from './counterSlice';
export function Counter() {
const count = useSelector((state) => state.counter.value); // Selects 'value' from 'counter' slice
const dispatch = useDispatch();
return (
<div>
<div>
<button
aria-label="Increment value"
onClick={() => dispatch(increment())}
>
Increment
</button>
<span>{count}</span>
<button
aria-label="Decrement value"
onClick={() => dispatch(decrement())}
>
Decrement
</button>
</div>
<div>
<input
type="number"
defaultValue="2"
onChange={(e) => dispatch(incrementByAmount(Number(e.target.value)))}
/>
<button
aria-label="Add amount"
onClick={() => dispatch(incrementByAmount(5))} // Example: add fixed amount
>
Add 5
</button>
</div>
</div>
);
}
// --- 4. src/App.js ---
import React from 'react';
import './App.css'; // Assuming you have some basic CSS
import { Counter } from './features/counter/Counter';
function App() {
return (
<div className="App">
<header className="App-header">
<h1>Redux Counter Example</h1>
<Counter />
</header>
</div>
);
}
export default App;
// --- 5. src/index.js ---
import React from 'react';
import { createRoot } from 'react-dom/client';
import './index.css'; // Your global styles
import App from './App';
import { store } from './app/store'; // Import the configured Redux store
import { Provider } from 'react-redux'; // Import Provider
const container = document.getElementById('root');
const root = createRoot(container);
root.render(
<React.StrictMode>
{/* Wrap the App component with the Redux Provider, passing the store */}
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>
);








Redux