Time to get in more depth of this topic. Until now (I mean in Day 7 Blog) we have seen basics of Redux. Now we will dive in more depth as a part of this blog’s agenda.
Lets re-visit what we have learnt until now.
Redux is a state management library. It helps you manage the state of your application in a centralized way. Redux can be used with any JavaScript framework, but it's most commonly used with React.
State: In Redux, all the application state (data) is stored in a single object called the store.
Flow: Redux uses a unidirectional data flow. There are 3 main concepts:
Action: Something happened (like a user clicked a button).
Reducer: How should the state change in response to that action?
Store: The current application state gets updated.
Lets explore (re-visit) a few key concepts.
Actions:
An action is a plain JavaScript object that describes what happened. Every action has a type
property that tells Redux what kind of action occurred.
const incrementAction = {
type: 'INCREMENT'
};
const decrementAction = {
type: 'DECREMENT'
};
You can also pass additional data along with the action, called a payload.
const setUserAction = {
type: 'SET_USER',
payload: {
name: 'John Doe',
age: 30
}
};
Reducers:
A reducer is a function that takes the current state and an action as input, and returns a new state. It defines how the state should change based on the action.
Example of a simple reducer:
const counterReducer = (state = 0, action) => {
switch (action.type) {
case 'INCREMENT':
return state + 1;
case 'DECREMENT':
return state - 1;
default:
return state;
}
};
In this example, the counterReducer
updates the state based on whether the action is 'INCREMENT'
or 'DECREMENT'
.
Store:
The store is the centralized place where your application state lives. You create a Redux store using the createStore
function. The store manages the following:
The current state.
Dispatching actions to trigger state updates.
Subscribing to state changes.
To create a store:
import { createStore } from 'redux';
import counterReducer from './reducers/counterReducer';
const store = createStore(counterReducer);
Time for Live Action Practical.
This will be our end product.
Whenever user clicks on Increment Button, the Counter value increases, as per the Action. When we click on Decrement Button, based on Action specified in the Reducer code, the number value decreases.
We will start by creating a basic reducer:
const counterReducer = (state = 0, action) => {
switch (action.type) {
case 'INCREMENT':
return state + 1;
case 'DECREMENT':
return state - 1;
default:
return state; // If no action matches, return current state
}
};
export default counterReducer;
This reducer increments or decrements the state based on the dispatched action i.e (INCREMENT / DECREMENT).
Now let us create a store:
// import { createStore } from 'redux'; ----> DEPRECATED
import { legacy_createStore as createStore} from 'redux'
import counterReducer from './reducers/counterReducer';
// Create the store using the counterReducer
const store = createStore(counterReducer);
export default store;
The store is created using createStore
and the counterReducer
we just made. Next, in your main entry file (likely index.js
), wrap your app inside the Provider
from react-redux
and pass it the store. So your index.js
should look something like this.
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import App from './App';
import store from './store'; // Import the store we created
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
Here, The Provider
makes the Redux store available to all components in the app.
Now it is time to dispatch the actions in your react component. In your React component (let’s use App.js
), we'll use useSelector
to access the current state and useDispatch
to dispatch actions.
import React from 'react';
import { useSelector, useDispatch } from 'react-redux'; // Import hooks
import { increment, decrement } from './actions/counterActions';
function App() {
const count = useSelector((state) => state); // Access the state
const dispatch = useDispatch(); // Create a dispatch function
return (
<div style={{ textAlign: 'center' }}>
<h1>Counter: {count}</h1>
<button onClick={() => dispatch({ type: 'INCREMENT' })}>Increment</button>
<button onClick={() => dispatch({ type: 'DECREMENT' })}>Decrement</button>
</div>
);
}
export default App;
Here we have used 2 more hooks.
useSelector Hook which retrieves the current state from the Redux store.
useDispatch Hook which dispatches actions to the store. Here, we directly dispatch actions for increment and decrement.
Oh yeah, just to be clear, this is how your file structure for this mini project should look like:
After all this steps, you will be able to view your counter app in working condition. Based on Actions, the app behaves accordingly.
To keep things simple
Reducer defines how the state changes.
Store holds the state.
Provider makes the store available to the whole app.
useSelector and useDispatch hooks allow components to interact with the store.
Assignment : You can add more complexity (like actions, multiple reducers, etc.)
In conclusion, we have taken a step-by-step approach to set up a basic Redux application in React. We explored how reducers, actions, store, and hooks like useSelector
and useDispatch
work together to manage state. Redux might seem overwhelming initially, but with this simplified example, we have covered the key concepts of Redux and how it integrates into a React application.
Whats Next then ??
Once you're comfortable with these fundamentals, you can explore more advanced Redux features like combining multiple reducers, handling asynchronous logic with middleware, and integrating Redux DevTools for debugging.
So That is it for this blog post. Do your assignments by upgrading the example we studied here.
Until then Ciao! Happy Coding.