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:

  1. Action is created: An action is created to describe a state change.
  2. Dispatch Action: The action is dispatched to the store using dispatch.
  3. Reducer Processes Action: The reducer function receives the action and returns a new state.
  4. Store Updates State: The Redux store updates the state with the new one returned by the reducer.
  5. 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:

  1. Counter Reducer: Manages a counter state.
  2. 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.js
const 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.js
const 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.js
import { 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.js
import { 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.js
import 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.js
import 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
  1. Single Source of Truth: Redux relies on a single store to keep the application state consistent and easy to manage.

  2. Complexity: Multiple stores make it harder to synchronize state and manage updates.

  3. 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.



so by using multiple reducers we have multiple state in store

Ans : Yes, exactly. When you use multiple reducers in Redux, you end up with a single
store that contains multiple slices of state, each managed by a different reducer.

How It Works:

  1. Multiple Reducers: Each reducer manages a specific part (slice) of the state.
  2. Single Store: All these slices are combined into one state object in the Redux 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:

  1. 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.

  2. 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.

  3. 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:

  1. 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.

  2. Easy Comparison: Since state objects don’t change, you can quickly check if state has been updated by comparing references.

  3. Debugging: Immutable state helps in tracking changes over time and using tools like time travel debugging to see past states.

  4. 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

Popular posts from this blog

ReactJS

Introduction To Java

ReactJs Interview Questions