State management is an essential aspect of any React application, as it determines how the different components of the app interact with each other and with the data they display. When developing large React apps, state management can be difficult and time-consuming, but libraries are available to help you handle your state management more effectively. One of these libraries is Redux.
Redux is a library that helps organize and manage the state of a React app in a centralized and predictable way. Redux provides a centralized store for managing the state of a React application. The store holds the application's state and allows components to access and update it. This article provides information to help you handle state management effectively using Redux.
Setting Up Redux in Your Application
To use redux
in a React application, you must first install the library by running the following command in your project’s directory on the terminal:
npm install redux
Alternatively, you run this command if you are using yarn
yarn add redux
After installing redux
, you install the react-redux
library. The react-redux
library is a library that binds React and Redux. It allows developers to use the Redux store and its functionality in a React application. The react-redux
library makes it easier to connect React components to the Redux store and manage the application's state.
To install react-redux
, run the following command:
npm install react-redux
Run this command, if you are making use of yarn
yarn add react-redux
Creating a Store Using the createStore Function
After installing the redux library, you need to create a store. A store holds the state of your application and allows the components to access and update it. You make the store using the createStore
function of the redux library. The createStore
function takes in three arguments, two are optional, and one is not. The two optional arguments are the initial state and an enhancer, and the non-optional argument is a reducer function.
A reducer function is a function that takes the current state of the application and returns the new state. The reducer updates the application’s state based on the dispatched actions. A reducer function takes two arguments state and action. The state
argument is the current state of the application, and the action
argument is an object that describes the action that occurred, including the type of the action.
An enhancer is a higher-order function that allows you to add functionality to the store, such as middleware for handling async actions or logging. A typical example of an enhancer is middleware. A middleware is a function that takes the store.dispatch
method as an argument and returns a new function that can be used to dispatch actions. Examples of enhancers are the redux-thunk
middleware, redux-logger
, redux-devtools-extension
, etc.
import { createStore } from 'redux';
const initialState = {
counter: 0
};
function reducer(state = initialState, action) {
switch (action.type) {
case 'INCREMENT':
return {
counter: state.counter + 1
};
case 'DECREMENT':
return {
counter: state.counter - 1
};
default:
return state;
}
}
const store = createStore(reducer, intialState);
export default store;
In the code block above, you import the createStore
function from the redux library and use it to create a store. The initialState
is an object containing the counter property. The state
argument of the reducer
function is set to initialState
by default.
The reducer function uses a switch statement to determine what to do based on the value of the action.type
property. If the value of action.type
is 'INCREMENT', the function returns a new object with the counter
property set to the current value of the counter plus 1. If the value of action.type
is 'DECREMENT,’ the function returns a new object with the counter
property set to the current value of the counter minus 1.
To create actions, you will create a function mapDispatchToProps
that takes the dispatch
method as an argument. Then using the dispatch
method, you will dispatch actions to the store.
For example:
export function mapDispatchToProps(dispatch) {
return {
increment: () => dispatch({type: 'INCREMENT'}),
decrement: () => dispatch({type: 'DECREMENT'})
}
}
The mapDispatchToProps
function returns an object with two properties, increment
, and decrement
, each of which is a function that dispatches an action to the store. Calling the increment
function will dispatch an action with the type 'INCREMENT' to the store. Calling the decrement
function will dispatch an action with the type ‘DECREMENT’ to the store.
Connecting Your Component to the Redux Store Using the Connect Function
To connect a component to the store and access the state, you use the connect
function from the react-redux
library. The connect
function takes two arguments: a function that maps the store's state to the props of the component and an object that maps action creators to the props of the component.
For example:
import { connect } from 'react-redux';
import { mapDispatchToProps } from './actions';
function Counter(props) {
return (
<div>
<h1>{props.counter}</h1>
<button onClick={props.increment}>Increment</button>
<button onClick={props.decrement}>Decrement</button>
</div>
);
}
function mapStateToProps(state) {
return {
counter: state.counter
};
}
export default connect(mapStateToProps, mapDispatchToProps)(Counter);
The connect
function takes two arguments: the mapStateToProps
function that maps the store's state to the props of the component and the mapDispatchToProps
function that returns an object that maps action creators to the props of the component. The component is then wrapped in a higher-order component (HOC) that handles the store interaction, and the resulting HOC component is returned. The component can access the state and action it needs from the store via its props.
Now you have created a store and connected your component to the store. However, for your store to be accessible to all your React components, you must utilize the provider
component from the react-redux library.
To ensure your store is available throughout your application, you import the provider
component from the react-redux
library into your app
component. The provider
component takes the store as a prop and makes it available to all child components. To ensure your entire application has access to the store, you wrap all your components within the provider
component.
Like so:
import { Provider } from 'react-redux';
import store from './store';
import Counter from './counter';
function App() {
return (
<Provider store={store}>
<Counter />
</Provider>
);
}
Handling Asynchronous Operations Using Redux-Thunk Middleware
The redux-thunk
middleware is a middleware for Redux that allows you to write action creators that return a function instead of an action object. In a Redux application, action creators return an action object with a type
and an optional payload
property. These action objects are dispatched to the store and passed to the reducer function, which updates the application’s state.
However, in some cases, you may need to perform async operations, such as making an API call, before dispatching an action. In these cases, you use redux-thunk
to write action creators that return a function instead of an action object. This function can then perform the async operation and dispatch the action.
Installing and Setting Up Redux-Thunk
To use the redux-thunk
middleware, you need to install it in your application. To install the middleware, run the following command in your project’s directory on the terminal:
npm install redux-thunk
After installing, you import the thunk
function from the middleware and pass it as an argument to the applyMiddleware
function of the redux library. The applyMiddleware
function is a function from the redux library that allows you to apply middleware to a Redux store.
Like so:
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import { reducer } from './reducer';
const middleware = [thunk];
const store = createStore(reducer, applyMiddleware(...middleware));
export default store;
In the code block above, the createStore
function is invoked with the reducer
function and the applyMiddleware
function. The applyMiddleware
function can take multiple middlewares as arguments.
After creating the store, you create your reducer and actions:
export function fetchData() {
return function (dispatch) {
fetch('https://jsonplaceholder.typicode.com/posts')
.then( (response) => response.json() )
.then( (data) => dispatch({
type: 'FETCH_POSTS',
payload: data
}) )
}
}
You created an action called fetchData
that, when called, dispatches an action of type FETCH_POSTS
with the payload of the data returned by the API.
Now, after creating your action, you proceed to create your reducer function:
const initialState = {
data: [],
};
export function reducer(state = initialState, action) {
switch (action.type) {
case 'FETCH_POSTS':
return {
data: action.payload,
};
default:
return state;
}
}
In the code block above, the initialState
is an object holding a single property, data
. The function uses the switch statement to check the type
property of the action object.
In this case, the only action type handled is FETCH_POSTS
. If the action's type is FETCH_POSTS
, it will return a new state object with the data
property set to the action’s payload. The action’s payload is the data that was fetched.
After creating your store, you connect your component to the store.
Like so:
import React from 'react';
import { connect } from 'react-redux';
import { fetchData } from './actions';
function Home(props) {
React.useEffect( props.fetchData, [] );
return(
{ props.data.map( (item) => ( <p key={item.id}>{item.body}</p> )) }
)
}
const mapStateToProps = (state) => ({
data: state.data
})
export default connect( mapStateToProps, { fetchData })(Home);
Conclusion
Redux is a powerful library that can help you handle state management in your React application. By using a centralized store, actions, and reducers, you can effectively manage the state of your application. By connecting your React components to the store using the react-redux library, you can easily access the state and dispatch actions from within your components. The middleware redux-thunk help in handling the async flow of the actions.
With the help of this article, you should now have a good understanding of how to set up and use Redux in your React application and how it can help you handle state management in a more efficient and manageable way.
Top comments (2)
I'm sorry to tell you that, but your article describes a very outdated style of Redux - since 2019 Redux looks very different from that. No more
createStore
, ACTION_TYPES, immutable switch..case reducers orconnect/mapStateToProps
. Please give redux.js.org/introduction/why-rtk-... a read.Thank you, I would look into it