0% found this document useful (0 votes)
31 views9 pages

Redux Notes

My redux notes
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
31 views9 pages

Redux Notes

My redux notes
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 9

State Management

What is useContext?
useContext is a React hook that allows components to share and consume data (state)
without passing props down manually through every level of the component tree. We can
avoid prop drilling by:

1. Create a context (like a global store).


2. Provide that context value at a top level.
3. Any component inside can read the context without prop drilling.

Example:

import { createContext, useContext } from "react";

// 1. Create Context
const ThemeContext = createContext("light");

function App() {
const theme = "dark";
// 2. Provide Context to children
return (
<ThemeContext.Provider value={theme}>
<Toolbar />
</ThemeContext.Provider>
);
}

function Toolbar() {
return (
<ThemeButton />
);
}

function ThemeButton() {
// 3. Consume Context value
const theme = useContext(ThemeContext);
return (
<button
style={{
backgroundColor: theme === "dark" ? "black" : "white",
color: theme === "dark" ? "white" : "black",
padding: "10px 20px",
}}
>
I am a {theme} themed button
</button>
);
}

export default App;


When NOT to use useContext

 When you have a very complex state or lots of actions to update state.
 When performance matters and you want to avoid unnecessary re-renders
(since useContext triggers re-renders for all consumers on every change).
 When you need features like middleware, time-travel debugging, or advanced
devtools (Redux is better here).

What is Redux?

Redux is a predictable state container (predictable means => states are not mutated or
not updated directly but rather are re-assigned) for JavaScript apps (including React). It helps
you manage your app’s state in a single, centralized store and makes state changes
predictable and easier to debug.

Core Concepts

Concept What It Is & Why Important

Store The single source of truth holding all app state.

Actions Plain objects describing what happened (e.g., { type: 'INCREMENT' }).

Pure functions that calculate the new state based on the current state
Reducers
and an action.

Dispatch The method to send actions to the store to update state.

Subscriber
Components or code that listen for state changes.
s

How Redux works — the flow

1. You dispatch an action describing what happened.


2. The reducer function receives the current state and the action.
3. The reducer returns a new state based on the action.
4. The store updates the state and notifies subscribers (e.g., UI components).
5. UI updates according to the new state.
Getting Started with Redux
 Redux is a JS library for maintainable global state management.
 The whole global state of the app is stored in an object tree inside a
single store. The only way to change the state tree is to create an action, an object
describing what happened, and dispatch it to the store. To specify how state gets updated
in response to an action, we write pure reducer functions that calculate a new state based
on the old state and the action.

Redux Core Concepts


a) Store
 The single source of truth for your app’s state.
 Holds the entire state object.
 Provides methods to get state, dispatch actions, and subscribe to changes.
b) Actions
 Plain JavaScript objects that describe what happened in the app.
 Must have a type property (string).
 Can carry extra data via a payload property.
 Example: { type: 'INCREMENT' } or { type: 'ADD_TODO', payload: 'Learn Redux' }.
c) Reducers
 Pure functions that take the current state and an action, and return a new state.
 Must not mutate the original state — always return a new object.
 Example:
function counterReducer(state = { count: 0 }, action) {
switch (action.type) {
case 'INCREMENT': return { count: state.count + 1 };
default: return state;
}
}
d) Dispatch
 The method used to send actions to the store.
 When you dispatch an action, Redux runs the reducer to update the state.
e) Selectors
 Functions used to select parts of the state.
 Helps separate state reading logic from components.
f) Subscribers
 Functions or components that listen to the store to be notified of state changes.

Redux Toolkit (RTK) Concepts


Redux Toolkit is the official, recommended way to write Redux code that reduces
boilerplate and improves DX (developer experience).
a) configureStore()
 A function that creates the Redux store with good defaults.
 Automatically sets up:
o Redux DevTools integration
o Middleware like Redux Thunk for async actions
o Combines reducers easily
b) createSlice()
 Combines reducers, actions, and action creators into one place.
 Automatically generates action creators and types.
 Uses Immer internally — lets you write reducers with “mutating” syntax safely.
c) createAsyncThunk()
 Simplifies writing async logic (e.g., API calls).
 Automatically generates lifecycle actions (pending, fulfilled, rejected).
 Works well with extraReducers to handle async state changes.
d) Immer
 A library used by RTK that allows writing mutating code in reducers while keeping
state immutable under the hood.
 This simplifies reducer code a lot.
e) React-Redux Hooks
 useSelector: Access Redux state in React components.
 useDispatch: Get the dispatch function to send actions.
 Hooks make React + Redux integration cleaner and easier than older HOCs or
connect().
f) Middleware
 Redux middleware lets you intercept and handle actions.
 RTK comes with Redux Thunk included by default, so you can dispatch async thunks
out of the box.
g) DevTools Integration
 RTK automatically enables Redux DevTools Extension for easier debugging and time-
traveling state inspection.

Benefits of Redux Toolkit Over Plain Redux

Plain Redux Redux Toolkit (RTK)


Lots of boilerplate code Minimal boilerplate, simple API
Manual action types & creators createSlice auto-generates them
Manual store setup configureStore sets up store with defaults
Manual async handling Built-in support for thunks with
(middleware) createAsyncThunk
Manual immutable updates Immer simplifies immutable updates

Code Example:
// slice.ts
import { createSlice } from "@reduxjs/toolkit";
const counterSlice = createSlice({
name: "counter",
initialState: {
value: 0
},
reducers: {
add: state => {
state.value += 1
},
addByValue: (state, action) => {
state.value += action.payload;
},
sub: state => {
state.value -= 1
},
}
})

export const { add, sub, addByValue } = counterSlice.actions;


export { counterSlice };

// store.ts
import { configureStore } from "@reduxjs/toolkit";
import { counterSlice } from "./slice";
const store = configureStore({
reducer: {
counter: counterSlice,
// user: userSlice - write as many slices as you want, configureStore automatically
combines them

});
export { store };
export type RootState = ReturnType<typeof store.getState>;

// App.tsx
import { Provider } from "react-redux";
import { store } from "./store";
import MainPage from "./MainPage";
const App = () => {
return (
<Provider store={store} >
<MainPage />
</Provider>
)
}
export default App;

// MainPage.tsx
import { useDispatch, useSelector } from "react-redux";
import { add, addByValue, sub } from "./slice";
import type { RootState } from "./store";

const MainPage = () => {


const value = useSelector((state: RootState) => state.counter.value);
const dispatch = useDispatch();
return (
<>
<div>MainPage value = {value}</div>
<button onClick={() => dispatch(add())}>Add</button>
<button onClick={() => dispatch(sub())}>Sub</button>
<button onClick={() => dispatch(addByValue(5))}>Add by 5</button>
</>
)
}

export default MainPage;

Middleware’s in Redux
Middleware in Redux is a function that runs between dispatching an action and
reaching the reducer.
It lets you:
 Intercept actions.
 Add logic like logging, async calls, conditionally dispatching new actions.
 Modify, delay, or cancel actions.
They are because:
1. Reducers must be pure and synchronous.
2. Middleware handles side effects like:
 API calls
 Logging
 Delaying actions
 Condition-based dispatching

Simple Middleware Flow

dispatch(action)-- > middleware-- > reducer-- > store updated

Creating a simple custom middleware

// logger.ts
import type { Middleware } from "@reduxjs/toolkit";
export const loggerMiddleware: Middleware = (storeAPI) => (next) => (action)=>{
console.log("Dispatching = ", action);
const result = next(action);
console.log("Next State = ", storeAPI.getState());
return result;
};

// update store to this


// store.ts
import { configureStore } from "@reduxjs/toolkit";
import { counterSlice } from "./slices/counterSlice";
import { userSlice } from "./slices/userSlice";
import { loggerMiddleware } from "./middlewares/logger";

const store = configureStore({


reducer: {
counter: counterSlice.reducer,
user: userSlice.reducer
},
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().concat(loggerMiddleware),
});

export { store };
export type RootState = ReturnType<typeof store.getState>;
// then using any reducers would run this middleware

createAsyncThunk is a helper function from Redux Toolkit that simplifies handling


asynchronous operations (e.g., API requests) in Redux.

It automatically creates three lifecycle action types:


 pending – when the async request is initiated.
 fulfilled – when the request completes successfully.
 rejected – when the request fails (e.g., network error).
This reduces boilerplate and ensures a consistent pattern for managing async state (loading,
success, error).
Simple Example by Fetching User

// features/user/userSlice.ts
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
import type { PayloadAction } from "@reduxjs/toolkit";

interface User {
id: number;
name: string;
email: string;
}

interface UserState {
user: User | null;
loading: boolean;
error: string | null;
}

const initialState: UserState = {


user: null,
loading: false,
error: null,
};

export const fetchUser = createAsyncThunk("user/fetchUser", async () => {


const response = await fetch("https://jsonplaceholder.typicode.com/users/1");
return response.json() as Promise<User>;
});

export const userSlice = createSlice({


name: "user",
initialState,
reducers: {},

extraReducers: (builder) => {


builder
.addCase(fetchUser.pending, (state) => {
state.loading = true;
state.error = null;
state.user = null;
})
.addCase(fetchUser.fulfilled, (state, action: PayloadAction<User>) => {
state.loading = false;
state.user = action.payload;
})
.addCase(fetchUser.rejected, (state, action) => {
state.loading = false;
state.error = action.error.message || "Failed to fetch user";
});
},
});

export default userSlice.reducer;

// app/store.ts
import { configureStore } from '@reduxjs/toolkit';
import userReducer from "./slices/userSlice";

export const store = configureStore({


reducer: {
user: userReducer,
},
});

export type RootState = ReturnType<typeof store.getState>;


export type AppDispatch = typeof store.dispatch;

import React from “react”;


import { useDispatch, useSelector } from “react-redux”;
import { fetchUser } from “./slices/userSlice”;
import type { RootState, AppDispatch } from ”./store”;

function App() {
const dispatch: AppDispatch = useDispatch();
const { user, loading, error } = useSelector((state: RootState) => state.user);

return (
<div style={{ padding: '2rem' }}>
<h1>Fetch User with createAsyncThunk</h1>
<button onClick={() => dispatch(fetchUser())}>Fetch User</button>

{loading && <p>Loading...</p>}


{error && <p style={{ color: 'red' }}>❌ {error}</p>}
{user && (
<div>
<p>👤 Name: {user.name}</p>
<p>📧 Email: {user.email}</p>
</div>
)}
</div>
);
}

export default App;


Redux State
Action UI Output
Change

fetchUser.pendi
Show "Loading..." loading: true
ng

fetchUser.fulfille Show user user set, loading:


d name/email false

fetchUser.reject Show error error set, loading:


ed message false

React-Redux Hooks
React Redux provides special hooks to access the Redux store and dispatch actions in
function components

Hook Description

useSelector Read data from the Redux store

useDispatch Send actions to the Redux store

useStore (less Access the underlying Redux store object


common) directly

You might also like