Managing Application State in React with Redux and ASP.NET Core
When building modern web applications, the React frontend and ASP.NET Core backend must work together smoothly. Redux helps manage complex state on the client, while ASP.NET Core provides APIs and data persistence on the server.
This guide covers how to structure your project, manage client–server state, and keep everything synchronized.
1. What Redux Solves in a React + ASP.NET Core App
React manages UI state, but complex applications often need global state such as:
Authenticated user data
Tokens and session details
Cart or dashboard data
Notifications
Global filters & settings
Data fetched from the ASP.NET Core API
Redux helps:
Store and update state globally
Keep UI consistent
Enable predictable state transitions
Support debugging with Redux DevTools
2. Project Architecture Overview
Frontend (React + Redux Toolkit)
Manages UI state
Calls ASP.NET Core API
Stores global and session state in Redux store
Uses slices to handle features
Backend (ASP.NET Core Web API)
Validates requests
Provides secure endpoints
Returns JSON data
Manages databases (EF Core, SQL Server, PostgreSQL, etc.)
Issues JWT tokens for authentication
3. Setting Up Redux Toolkit
Install Redux Toolkit and React Redux:
npm install @reduxjs/toolkit react-redux
Create the Redux store
// store.js
import { configureStore } from '@reduxjs/toolkit';
import authReducer from './slices/authSlice';
import productsReducer from './slices/productsSlice';
export const store = configureStore({
reducer: {
auth: authReducer,
products: productsReducer
}
});
Wrap the React app:
import { Provider } from 'react-redux';
import { store } from './store';
root.render(
<Provider store={store}>
<App />
</Provider>
);
4. Using Redux Toolkit Slices
✔ Example: Authentication Slice
// slices/authSlice.js
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
import axios from 'axios';
export const login = createAsyncThunk(
'auth/login',
async (credentials) => {
const response = await axios.post('/api/auth/login', credentials);
return response.data; // JWT + user info
}
);
const authSlice = createSlice({
name: 'auth',
initialState: {
user: null,
token: null,
status: 'idle'
},
reducers: {
logout(state) {
state.user = null;
state.token = null;
}
},
extraReducers: (builder) => {
builder.addCase(login.fulfilled, (state, action) => {
state.user = action.payload.user;
state.token = action.payload.token;
});
}
});
export const { logout } = authSlice.actions;
export default authSlice.reducer;
This slice lets Redux manage authentication state, including the JWT returned from ASP.NET Core.
5. Consuming ASP.NET Core API from Redux
Use createAsyncThunk to call backend endpoints.
Example: Fetching products:
// slices/productsSlice.js
export const fetchProducts = createAsyncThunk(
'products/fetchAll',
async () => {
const response = await axios.get('/api/products');
return response.data;
}
);
Reducers update the global store when data arrives.
6. Securing API Requests with JWT (ASP.NET Core)
ASP.NET Core Login Endpoint Example
[HttpPost("login")]
public IActionResult Login([FromBody] LoginModel model)
{
var user = Authenticate(model.Username, model.Password);
if (user == null) return Unauthorized();
var token = GenerateJwtToken(user);
return Ok(new { user, token });
}
Decode the token in React and store it in Redux:
dispatch(login({ username, password }));
7. Adding JWT to Axios Requests (Frontend)
When logged in, attach the token to every request:
axios.interceptors.request.use((config) => {
const token = store.getState().auth.token;
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
});
8. Keeping Redux and ASP.NET Core in Sync
✔ State that should live in Redux (frontend):
UI state (loading, dialogs, filters)
Logged-in user info
Temporary form data
Cached API responses
✔ State that should live in ASP.NET Core (backend):
Database records
Business rules
Authentication & authorization
Secure data
✔ Synchronization strategy:
Frontend → dispatch action
Redux thunk → calls ASP.NET Core endpoint
ASP.NET Core processes the request and returns data
Redux reducers update the global store
UI re-renders with fresh state
9. Example Workflow: Updating a User Profile
Step 1: User clicks "Save"
React dispatches:
dispatch(updateUser(formData));
Step 2: Thunk calls API
export const updateUser = createAsyncThunk(
'auth/updateUser',
async (data) => {
const response = await axios.put('/api/users/me', data);
return response.data;
}
);
Step 3: ASP.NET Core updates database
[Authorize]
[HttpPut("me")]
public async Task<IActionResult> UpdateProfile(UserDto dto)
{
var user = await _userService.UpdateAsync(dto);
return Ok(user);
}
Step 4: Redux updates state globally
builder.addCase(updateUser.fulfilled, (state, action) => {
state.user = action.payload;
});
React UI updates automatically.
10. Best Practices for React + Redux + ASP.NET Core
Frontend
Use Redux Toolkit (not legacy Redux)
Keep UI-only state out of Redux
Handle loading & error states
Store JWT securely (httpOnly cookies recommended)
Use thunks for all API calls
Backend
Use ASP.NET Core Identity or JWT
Validate every request
Use DTOs instead of exposing database models
Enable CORS for your frontend
Log and handle errors consistently
Architecture
Treat Redux as your “client-side source of truth”
Treat ASP.NET Core as the “server-side source of truth”
Avoid duplicating business logic in React
11. Folder Structure Example
Frontend (React)
src/
app/
store.js
slices/
authSlice.js
productsSlice.js
components/
pages/
Backend (ASP.NET Core)
Controllers/
Services/
Models/
DTOs/
Repositories/
Startup.cs or Program.cs
Summary
Managing application state in a React + Redux + ASP.NET Core app involves:
Using Redux Toolkit for clean, predictable state management
Fetching and updating data through ASP.NET Core Web APIs
Keeping authentication state (JWT) in Redux
Synchronizing server and client state with async thunks
Protecting APIs with JWT and validating on the backend
Using Redux slices to organize features cleanly
This approach provides a scalable, maintainable, and secure architecture.
Learn Dot Net Course in Hyderabad
Read More
Component-Based Development in Blazor
Introduction to TailwindCSS for Full Stack .NET Developers
Implementing Lazy Loading in Full Stack .NET Applications
How to Implement Real-Time Features with SignalR and React
Visit Our Quality Thought Institute in Hyderabad
Subscribe by Email
Follow Updates Articles from This Blog via Email
No Comments