Redux
REDUX :
1. Explain flow of redux :
1. Action
An action is a plain JavaScript object that describes a change or an event that occurred in the application. It has a type
property (a string that indicates the action) and can optionally have a payload
property (additional data needed to perform the action).
- Example of an Action:const addItemAction = {
type: 'ADD_ITEM', payload: { id: 1, name: 'Book' } };
2. Dispatch
To initiate a change, an action must be sent to the Redux store using the dispatch
function. The dispatch
function is a method provided by the Redux store, and it's the only way to trigger a state change.
- Example of Dispatching an Action:store.dispatch(addItemAction);
3. Reducer
Reducers are pure functions that determine how the state of the application changes in response to an action. A reducer takes the current state and an action as arguments and returns a new state.
- Example of a Reducer:const initialState = { items: [] };
function itemReducer(state = initialState, action) { switch (action.type) { case 'ADD_ITEM': return { ...state, items: [...state.items, action.payload] }; default: return state; } }
4. Store
The store is a central object that holds the application's state. It is created using the createStore
function from Redux. The store provides methods such as dispatch
, getState
, and subscribe
.
- Example of Creating a Store:import { createStore } from 'redux';
const store = createStore(itemReducer);
5. State
The state is a single JavaScript object that represents the entire state of the application. The state can only be updated by dispatching actions to the store.
- Accessing the State:const currentState = store.getState();
6. View (React Component)
In a React-Redux application, components are connected to the Redux store to access the state and dispatch actions. React components can subscribe to the store's updates, and when the state changes, the components automatically re-render.
- Example of Connecting a React Component:import React from 'react';
import { useSelector, useDispatch } from 'react-redux'; function ItemList() { const items = useSelector((state) => state.items); // Access state const dispatch = useDispatch(); const addItem = () => { dispatch({ type: 'ADD_ITEM', payload: { id: 2, name: 'Pen' } }); }; return ( <div> <ul> {items.map((item) => ( <li key={item.id}>{item.name}</li> ))} </ul> <button onClick={addItem}>Add Item</button> </div> ); }
Redux Flow Summary:
- Action is created: An action is created to describe a state change.
- Dispatch Action: The action is dispatched to the store using
dispatch
. - Reducer Processes Action: The reducer function receives the action and returns a new state.
- Store Updates State: The Redux store updates the state with the new one returned by the reducer.
- View Re-Renders: The React component subscribed to the store detects the state change and re-renders to reflect the new state.
Redux Flow Diagram:
Action -> Dispatch -> Reducer -> Store -> State -> React View (Component)
Simple Example: Multiple Reducers in React with Redux
In this example, we will create a simple application with two reducers:
- Counter Reducer: Manages a counter state.
- User Reducer: Manages user information.
1. Install Dependencies
Make sure you have the necessary packages installed:
npm install redux react-redux
2. Create the Reducers
We'll create two reducers: counterReducer
and userReducer
.
counterReducer.js
This reducer will handle actions related to a counter.
// counterReducer.jsconst initialCounterState = {
count: 0
};
const counterReducer = (state = initialCounterState, 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;
userReducer.js
This reducer will handle actions related to user information.
// userReducer.jsconst initialUserState = {
name: ''
};
const userReducer = (state = initialUserState, action) => {
switch (action.type) {
case 'SET_USER_NAME':
return {
...state,
name: action.payload
};
default:
return state;
}
};
export default userReducer;
3. Combine the Reducers
Use the combineReducers
function to combine the two reducers into a single root reducer.
rootReducer.js
// rootReducer.jsimport { combineReducers } from 'redux';
import counterReducer from './counterReducer';
import userReducer from './userReducer';
// Combine reducers
const rootReducer = combineReducers({
counter: counterReducer,
user: userReducer
});
export default rootReducer;
4. Create the Store
Create the Redux store using the combined reducer.
store.js
// store.jsimport { createStore } from 'redux';
import rootReducer from './rootReducer';
// Create Redux store with the combined reducer
const store = createStore(rootReducer);
export default store;
5. Integrate Redux with React
Now, wrap your React app with the Provider
to connect it to the Redux store.
index.js
// index.jsimport React from 'react';
import ReactDOM from 'react-dom/client';
import { Provider } from 'react-redux';
import App from './App';
import store from './store';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<Provider store={store}>
<App />
</Provider>
);
6. Create the React Component
Connect the React component to the Redux store using useSelector
to access the state
and useDispatch
to dispatch actions.
App.js
// App.jsimport React from 'react';
import { useSelector, useDispatch } from 'react-redux';
const App = () => {
const count = useSelector((state) => state.counter.count); // Access counter state
const userName = useSelector((state) => state.user.name); // Access user state
const dispatch = useDispatch();
const increment = () => {
dispatch({ type: 'INCREMENT' });
};
const decrement = () => {
dispatch({ type: 'DECREMENT' });
};
const setUserName = (name) => {
dispatch({ type: 'SET_USER_NAME', payload: name });
};
return (
<div>
<h1>Counter: {count}</h1>
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
<h2>User Name: {userName}</h2>
<button onClick={() => setUserName('Anjali')}>Set User Name</button>
</div>
);
};
export default App;
Explanation of the Code
- Reducers:
counterReducer
manages the counter state (count
).userReducer
manages the user state (name
).
- Combined Reducer:
combineReducers
merges both reducers into a single rootReducer
.
- Store:
- The store is created using the
rootReducer
and made available to the entire app
through the Provider
.
- React Component (
App.js
):useSelector
is used to access different parts of the state (counter
and user
).useDispatch
is used to dispatch actions (INCREMENT
, DECREMENT
, SET_USER_NAME
).
Can we have multiple store in redux ?Ans :
We cant have multiple store in redux because Single Source of Truth: Redux relies on a single store to keep the application state
consistent and easy to manage.
Complexity: Multiple stores make it harder to synchronize state and manage updates.
Middleware and Debugging: Redux middleware and tools are designed for a single store,
making them less effective with multiple stores.
Solution: Use combineReducers
to manage different parts of state within one store.
What are reducers ?Ans :
Reducers are functions in Redux that manage how the state of an application changes in
response to actions. They are pure functions, meaning they do not modify the existing
state but instead return a new state based on the action received.
Key Points About Reducers:
Pure Functions: Reducers take the current state and an action as arguments and
return a new state. They should not mutate the original state or have side effects.
State Management: Each reducer manages a specific slice of the state.
For example, you might have one reducer for user data and another for product data.
Combining Reducers: When you have multiple reducers, you use combineReducers
to
combine them into a single root reducer. This root reducer will then be used to create
the Redux store.
Why reducers are pure functions :Ans :Consistent Output: Given the same input (current state and action),
a pure function always returns the same output (new state).
This consistency helps in predicting how state changes over time.
No Side Effects: Pure functions don’t cause changes outside of themselves.
They only use their input arguments to produce an output.
This means reducers don't alter other parts of the system or depend on external factors like
network requests or random values.
Immutability: Instead of changing the existing state, a pure function returns a new state.
This approach avoids unintended side effects and makes it easier to track and
debug state changes.
Predictability: Because the reducer function always produces the same result for the
same inputs, it's easier to understand and predict how the state will change.
Why State is Immutable in Redux:
Predictability: Immutable state means once you set it, it doesn’t change. This makes
it easier to predict how state will evolve with each action.
Easy Comparison: Since state objects don’t change, you can quickly check if state has
been updated by comparing references.
Debugging: Immutable state helps in tracking changes over time and using tools like
time travel debugging to see past states.
No Side Effects: Immutability prevents accidental changes to the state, reducing bugs
and unintended behavior.
Example:
Instead of changing the state directly, you return a new state:
const initialState = { count: 0 };
const counterReducer = (state = initialState, action) => {
switch (action.type) {
case 'INCREMENT':
return { ...state, count: state.count + 1 }; // New state
default:
return state; // Same state if no action matches
}
};
Here, { ...state, count: state.count + 1 }
creates a new state object without changing the
old one.
Comments
Post a Comment