Check out my Medium articles here: My Medium Articles 🚀
Redux Basics: A Detailed Explanation with Code Examples
Redux is a state management library used widely with JavaScript applications, especially with React. It provides a centralized store for the state of your app, making it easier to manage and debug, especially in large and complex applications. Redux follows a unidirectional data flow and ensures that state changes happen in a predictable manner, making it easier to understand how your app works.
Let's break down the Redux basics step by step, explaining each concept with code examples.
1. What is Redux?
Redux is a predictable state container for JavaScript apps. It helps you manage the state of your app in a centralized way, making it easier to debug and scale.
Core Principles of Redux:
- Single Source of Truth: The whole state of the application is stored in a single object (the store), making it easy to track and manipulate.
- State is Read-Only: The only way to change the state is by dispatching an action.
- Changes are Made with Pure Functions: State is modified by reducers, which are pure functions that specify how the state changes in response to an action.
2. Core Concepts of Redux
Redux relies on the following key components:
1. Action
An action is a plain JavaScript object that describes an event or an action that has occurred in the application. Each action must have a type property, which describes the action being performed.
Action Example:
// actions.js
export const increment = () => ({
type: 'INCREMENT'
});
export const decrement = () => ({
type: 'DECREMENT'
});
- Here,
incrementanddecrementare action creators. They return action objects with atypefield. Thetypeproperty tells Redux how to handle the action in the reducer.
2. Reducer
A reducer is a pure function that takes the current state and an action, then returns a new state. Reducers are the functions that specify how the state should change in response to an action. They should be pure functions, meaning they don’t modify the original state but return a new state object.
Reducer Example:
// reducer.js
const initialState = {
count: 0
};
const counterReducer = (state = initialState, action) => {
switch (action.type) {
case 'INCREMENT':
return { ...state, count: state.count + 1 };
case 'DECREMENT':
return { ...state, count: state.count - 1 };
default:
return state;
}
};
export default counterReducer;
- In the example above:
- The initial state is defined with a
countof0. - The reducer listens for actions
INCREMENTandDECREMENTand updates thecountstate accordingly. - The
return { ...state, count: state.count + 1 }line creates a new object to maintain immutability and update the state.
- The initial state is defined with a
3. Store
The store holds the entire state of your application. The store is created using the createStore method from Redux, and it is where the application’s state lives. The store also provides methods to dispatch actions and subscribe to changes in the state.
Store Example:
// store.js
import { createStore } from 'redux';
import counterReducer from './reducer';
const store = createStore(counterReducer);
export default store;
- The store is created by passing the
counterReducertocreateStore. - Now, the state of the application is managed by Redux, and any changes to the state will go through the reducer.
3. Connecting Redux with React
React components need to interact with the Redux store to get the state and dispatch actions. React-Redux, a separate library, is used to connect React with Redux. It provides hooks like useSelector to access the store’s state and useDispatch to dispatch actions.
Steps to Connect Redux with React:
-
Wrap your app with the
Providercomponent fromreact-reduxto pass the store to all your components. - Use
useSelectorto access the state. - Use
useDispatchto dispatch actions that modify the state.
4. Setting Up Redux in a React App
Let’s walk through the complete setup to connect Redux with a simple React app.
Step 1: Install Redux and React-Redux
First, you need to install Redux and React-Redux:
npm install redux react-redux
Step 2: Create Actions
In Redux, actions are plain JavaScript objects that describe the change you want to make to the state.
// actions.js
export const increment = () => ({
type: 'INCREMENT'
});
export const decrement = () => ({
type: 'DECREMENT'
});
- The
incrementanddecrementfunctions are action creators that return action objects. - The action object has a
typefield that describes the action.
Step 3: Create a Reducer
A reducer is a function that takes the current state and an action, and returns a new state.
// reducer.js
const initialState = {
count: 0
};
const counterReducer = (state = initialState, action) => {
switch (action.type) {
case 'INCREMENT':
return { ...state, count: state.count + 1 };
case 'DECREMENT':
return { ...state, count: state.count - 1 };
default:
return state;
}
};
export default counterReducer;
- The reducer listens for the
INCREMENTandDECREMENTactions and updates the state accordingly.
Step 4: Create the Store
The store is where the state lives. It is created using the createStore method from Redux.
// store.js
import { createStore } from 'redux';
import counterReducer from './reducer';
const store = createStore(counterReducer);
export default store;
- We pass the
counterReducertocreateStoreto create a store that will manage the state for our app.
Step 5: Connecting Redux with React
Now, let's connect Redux to our React app using the Provider, useDispatch, and useSelector hooks.
// App.js
import React from 'react';
import { Provider, useDispatch, useSelector } from 'react-redux';
import store from './store';
import { increment, decrement } from './actions';
const Counter = () => {
const count = useSelector((state) => state.count); // Get count from the store
const dispatch = useDispatch(); // Get dispatch function to send actions
return (
<div>
<p>Count: {count}</p>
<button onClick={() => dispatch(increment())}>Increment</button>
<button onClick={() => dispatch(decrement())}>Decrement</button>
</div>
);
};
const App = () => {
return (
<Provider store={store}> {/* Provide the Redux store to the app */}
<Counter />
</Provider>
);
};
export default App;
-
Provider: Wraps the entire application, passing the Redux store down to all components. -
useSelector: Retrieves the current state (count) from the Redux store. -
useDispatch: Allows you to dispatch actions (incrementanddecrement).
5. Redux Toolkit (Optional)
To make Redux easier to use, Redux Toolkit simplifies setup by reducing boilerplate code. It offers utilities like createSlice and configureStore to handle common tasks such as creating reducers and configuring the store.
Example Using Redux Toolkit:
import { configureStore, createSlice } from '@reduxjs/toolkit';
// Define a slice of state
const counterSlice = createSlice({
name: 'counter',
initialState: { count: 0 },
reducers: {
increment: (state) => {
state.count += 1;
},
decrement: (state) => {
state.count -= 1;
}
}
});
// Configure store
const store = configureStore({
reducer: counterSlice.reducer
});
export default store;
- The
createSlicefunction automatically generates action creators and reducers for you. -
configureStoresimplifies store setup.
6. Best Practices for Using Redux
- Keep Redux for Global State: Use Redux for managing application-wide state (e.g., user authentication, settings).
-
Use Local State for Simple Components: For smaller state needs (like form inputs), use React's
useStateinstead of Redux. - Avoid Direct Mutation: Always return a new object when updating state to ensure immutability.
7. Conclusion
Redux is a powerful tool for managing global state in React applications. By understanding actions, reducers, and the store, you can manage complex state in a predictable way. Using Redux Toolkit can simplify this process further. When used correctly, Redux can make large applications easier to manage, debug, and scale.
With this knowledge, you're now equipped to incorporate Redux into your React applications, ensuring more efficient state management across your app.
Top comments (0)