Redux Basics
Introduction
Redux is a popular JavaScript library used for managing and centralizing application state. It provides a predictable, centralized state container that helps you build applications that behave consistently. While React’s built-in state management is powerful, it can become challenging to manage complex, large-scale applications as they grow. Redux is especially useful for applications with dynamic or shared data and provides a clear pattern for handling global state.
In this lesson, you’ll learn:
- What Redux is and why it’s useful for state management
- The core concepts of Redux, including actions, reducers, and the store
- How to set up Redux in a React application
What is Redux?
Redux is a state management library that centralizes the application’s state in a single store. In Redux, data flow is unidirectional and predictable, making it easier to track, debug, and manage the application's state. Redux is not tied to any specific framework and can be used with various JavaScript libraries, but it’s most commonly used with React.
Key principles of Redux include:
- Single Source of Truth: All application state is kept in a single store.
- State is Read-Only: The only way to modify state is by dispatching actions, ensuring consistency.
- Changes are Made with Pure Functions: Reducers are pure functions that take the previous state and an action and return the next state.
When to Use Redux
Redux is ideal for applications where:
- The state needs to be shared among multiple components.
- The application’s state changes frequently.
- Data from different parts of the app needs to be updated based on user interactions.
- Managing complex state or performing actions based on asynchronous data (e.g., fetching data from an API) is required.
If your app has minimal shared or global state, using Redux may be unnecessary overhead, and the Context API or React’s local state may be sufficient.
Core Concepts of Redux
The Redux library is based on several key concepts:
- Store: The centralized location where the entire application’s state is managed.
- Action: An object describing a change or event in the application, containing a
type
and optionalpayload
. - Reducer: A pure function that takes the current state and an action and returns the next state.
- Dispatch: A function used to send actions to the store to trigger state changes.
- Selector: A function used to retrieve specific data from the Redux store.
Setting Up Redux in a React Application
To use Redux in a React app, you’ll need to install the Redux and React-Redux libraries. React-Redux provides bindings for connecting Redux with React components.
Step 1: Installing Redux and React-Redux
npm install redux react-redux
Creating a Basic Redux Setup
In this section, we’ll create a simple Redux setup for managing a counter application.
Step 2: Creating Actions
Actions are objects that describe events or changes in the application. Every action has a type
property that indicates the type of action being performed, and it may include a payload
with additional data.
Example: Defining Action Types and Action Creators
Create an actions.js
file to define your action types and creators.
// actions.js
// Action Types
export const INCREMENT = 'INCREMENT';
export const DECREMENT = 'DECREMENT';
// Action Creators
export const increment = () => ({
type: INCREMENT,
});
export const decrement = () => ({
type: DECREMENT,
});
In this example:
INCREMENT
andDECREMENT
are action types.increment
anddecrement
are action creators, functions that return an action object.
Step 3: Creating Reducers
Reducers are pure functions that handle the state changes based on the dispatched actions. They take the current state and an action as arguments and return the next state.
Example: Creating a Reducer
Create a reducer.js
file to define your reducer.
// reducer.js
import { INCREMENT, DECREMENT } from './actions';
const initialState = {
count: 0,
};
function 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 this example:
counterReducer
listens forINCREMENT
andDECREMENT
actions.- Based on the action type, it updates the
count
value and returns the new state.
Step 4: Creating the Redux Store
The store is the centralized place where all of the application’s state lives. To create a store, use Redux’s createStore()
function, which takes the reducer as an argument.
Example: Setting Up the Store
// store.js
import { createStore } from 'redux';
import counterReducer from './reducer';
const store = createStore(counterReducer);
export default store;
In this example:
createStore(counterReducer)
creates a Redux store using thecounterReducer
we defined earlier.
Connecting Redux to React
Now that we have the store, actions, and reducer set up, we need to connect Redux to React components using React-Redux’s <Provider />
component and useSelector
and useDispatch
hooks.
Step 5: Providing the Redux Store
Wrap your app in the Redux <Provider />
component and pass the store as a prop. This makes the store accessible to all components within the app.
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import App from './App';
import store from './store';
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
In this example:
- The
<Provider />
component is provided byreact-redux
and allows access to the Redux store throughout the app.
Step 6: Accessing State with useSelector
The useSelector
hook allows components to read data from the Redux store.
Example: Using useSelector
to Access State
import React from 'react';
import { useSelector } from 'react-redux';
const CounterDisplay = () => {
const count = useSelector((state) => state.count);
return <h1>Count: {count}</h1>;
};
export default CounterDisplay;
In this example:
useSelector
takes a function that receives the store’s state and returns the specific part of the state that we need (count
in this case).
Step 7: Dispatching Actions with useDispatch
The useDispatch
hook provides the dispatch
function, allowing components to send actions to the Redux store to trigger state changes.
Example: Using useDispatch
to Send Actions
import React from 'react';
import { useDispatch } from 'react-redux';
import { increment, decrement } from './actions';
const CounterControls = () => {
const dispatch = useDispatch();
return (
<div>
<button onClick={() => dispatch(increment())}>Increment</button>
<button onClick={() => dispatch(decrement())}>Decrement</button>
</div>
);
};
export default CounterControls;
In this example:
useDispatch
provides thedispatch
function, which allows you to trigger actions likeincrement()
anddecrement()
when the buttons are clicked.
Complete Example: Counter App with Redux
Here’s how all the parts fit together in a simple Counter app:
// App.js
import React from 'react';
import CounterDisplay from './CounterDisplay';
import CounterControls from './CounterControls';
const App = () => (
<div>
<CounterDisplay />
<CounterControls />
</div>
);
export default App;
In this example:
CounterDisplay
displays the current count usinguseSelector
.CounterControls
allows incrementing or decrementing the count usinguseDispatch
.
Conclusion
In this lesson, you’ve learned:
- The basics of Redux, including actions, reducers, and the store
- How to set up Redux in a React application
- How to use
useSelector
anduseDispatch
to connect components to the Redux store
Redux is a powerful tool for managing complex, shared state in React applications, especially as your app grows. In the next lesson, you’ll learn about middleware in Redux, including how to handle asynchronous actions with tools like redux-thunk
and redux-saga
.