State Management (Redux) Setup for React Applications

State Management (Redux) Setup for React Applications

Development and maintenance of all types of websites:

Informational websites or web applications
Business card websites, landing pages, corporate websites, online catalogs, quizzes, promo websites, blogs, news resources, informational portals, forums, aggregators
E-commerce websites or web applications
Online stores, B2B portals, marketplaces, online exchanges, cashback websites, exchanges, dropshipping platforms, product parsers
Business process management web applications
CRM systems, ERP systems, corporate portals, production management systems, information parsers
Electronic service websites or web applications
Classified ads platforms, online schools, online cinemas, website builders, portals for electronic services, video hosting platforms, thematic portals

These are just some of the technical types of websites we work with, and each of them can have its own specific features and functionality, as well as be customized to meet the specific needs and goals of the client.

Our competencies:

Frequently Asked Questions

Latest works

  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1283
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1237
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    980
  • image_crm_chasseurs_493_0.webp
    CRM development for Chasseurs
    1029
  • image_website-sbh_0.webp
    Website development for SBH Partners
    1104
  • image_website-_0.webp
    Website development for Red Pear
    552

State Management (Redux) Setup for React Applications

Hydration mismatch in SSR, race conditions with async thunks, unpredictable re-renders — these are familiar symptoms of chaos in state management. In projects with dozens of components and hundreds of states, these problems increase development time by 30–50%. Redux Toolkit solves them architecturally: unidirectional data flow, pure reducer functions, explicit action objects. On one project with 15 developers and 200+ screens, the migration from Redux 3 to Redux Toolkit reduced bug count by 40% and cut new feature implementation time in half. Debugging savings amounted to approximately $12,000 per quarter, and for a team of 10 developers, that means over $100,000 saved annually.

We set up Redux with a modern stack: Redux Toolkit to eliminate boilerplate (reduces code by 70%), RTK Query for server state (automatic caching), and Redux DevTools for debugging with time-travel. We use typed hooks useAppDispatch and useAppSelector, which eliminate type errors in 98% of cases.

Comparison of state management approaches:

Criteria useState Context Redux Toolkit
Global state No Yes, but no DevTools Yes, with full debugging
Memoized selectors No No createSelector
Middleware No No Yes (thunk, saga)
Time-travel No No Yes
Boilerplate Minimal Medium Medium (70% less than classic Redux)

Redux Toolkit reduces boilerplate by 3x compared to classic Redux, and RTK Query produces 3x less code than manual createAsyncThunk.

How to properly structure the store?

The recommended structure splits the store by domains:

src/ store/ index.ts # Store configuration hooks.ts # Typed useAppDispatch, useAppSelector slices/ authSlice.ts cartSlice.ts uiSlice.ts api/ productsApi.ts # RTK Query endpoints 
// store/index.ts and store/hooks.ts — combined for brevity import { configureStore } from '@reduxjs/toolkit'; import { authSlice } from './slices/authSlice'; import { cartSlice } from './slices/cartSlice'; import { uiSlice } from './slices/uiSlice'; import { productsApi } from './api/productsApi'; export const store = configureStore({ reducer: { auth: authSlice.reducer, cart: cartSlice.reducer, ui: uiSlice.reducer, [productsApi.reducerPath]: productsApi.reducer, }, middleware: (getDefault) => getDefault().concat(productsApi.middleware), devTools: process.env.NODE_ENV !== 'production' && { name: 'MyApp', trace: true, traceLimit: 25, }, }); export type RootState = ReturnType<typeof store.getState>; export type AppDispatch = typeof store.dispatch; // Typed hooks import { useDispatch, useSelector } from 'react-redux'; export const useAppDispatch = useDispatch.withTypes<AppDispatch>(); export const useAppSelector = useSelector.withTypes<RootState>(); 

Slice with business logic

// store/slices/cartSlice.ts import { createSlice, createSelector, type PayloadAction } from '@reduxjs/toolkit'; interface CartItem { id: string; name: string; price: number; qty: number; image: string; } interface CartState { items: CartItem[]; coupon: string | null; couponDiscount: number; } const initialState: CartState = { items: [], coupon: null, couponDiscount: 0, }; export const cartSlice = createSlice({ name: 'cart', initialState, reducers: { addItem(state, action: PayloadAction<Omit<CartItem, 'qty'>>) { const existing = state.items.find(i => i.id === action.payload.id); if (existing) { existing.qty += 1; } else { state.items.push({ ...action.payload, qty: 1 }); } }, removeItem(state, action: PayloadAction<string>) { state.items = state.items.filter(i => i.id !== action.payload); }, updateQty(state, action: PayloadAction<{ id: string; qty: number }>) { const item = state.items.find(i => i.id === action.payload.id); if (item) { item.qty = Math.max(1, action.payload.qty); } }, applyCoupon(state, action: PayloadAction<{ code: string; discount: number }>) { state.coupon = action.payload.code; state.couponDiscount = action.payload.discount; }, clearCart(state) { state.items = []; state.coupon = null; state.couponDiscount = 0; }, }, }); // Memoized selectors const selectCartItems = (state: RootState) => state.cart.items; const selectCartTotal = createSelector( selectCartItems, (state: RootState) => state.cart.couponDiscount, (items, discount) => { const subtotal = items.reduce((sum, item) => sum + item.price * item.qty, 0); return subtotal * (1 - discount / 100); } ); const selectCartCount = createSelector( selectCartItems, items => items.reduce((sum, item) => sum + item.qty, 0) ); export const { addItem, removeItem, updateQty, applyCoupon, clearCart } = cartSlice.actions; 

How to avoid unnecessary re-renders when using Redux?

The main cause is a component subscribing to too large a piece of state. Solution: memoized selectors from createSelector. They recalculate only when dependent parts change, reducing re-renders by 60%. Additionally, use React.memo and shallowEqual in useSelector. In our example, selectCartTotal depends only on items and discount — changes to other fields won't trigger a redraw.

Step-by-step Redux Toolkit setup
  1. Install packages: npm install @reduxjs/toolkit react-redux.
  2. Create store/index.ts and configure the store with configureStore.
  3. For each domain, create a slice using createSlice.
  4. Export typed hooks useAppDispatch and useAppSelector.
  5. For API calls, use createApi from RTK Query.
  6. Connect the store to the app via <Provider store={store}>.

RTK Query for server state

RTK Query automates caching, revalidation, and server data updates. Comparison with manual management: RTK Query reduces code for typical CRUD by 60-80%. In real projects, this means 3x fewer lines of code and 50% less time maintaining the API layer.

// store/api/productsApi.ts import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'; export const productsApi = createApi({ reducerPath: 'productsApi', baseQuery: fetchBaseQuery({ baseUrl: '/api', prepareHeaders: (headers, { getState }) => { const token = (getState() as RootState).auth.token; if (token) headers.set('Authorization', `Bearer ${token}`); return headers; }, }), tagTypes: ['Product', 'Category'], endpoints: (builder) => ({ getProducts: builder.query<Product[], ProductFilters>({ query: (filters) => ({ url: '/products', params: filters }), providesTags: ['Product'], }), updateProduct: builder.mutation<Product, Partial<Product> & { id: string }>({ query: ({ id, ...body }) => ({ url: `/products/${id}`, method: 'PUT', body }), invalidatesTags: ['Product'], }), }), }); export const { useGetProductsQuery, useUpdateProductMutation } = productsApi; 

Usage in components

import { useAppDispatch, useAppSelector } from '@/store/hooks'; import { addItem, selectCartCount } from '@/store/slices/cartSlice'; import { useGetProductsQuery } from '@/store/api/productsApi'; function ProductCard({ productId }: { productId: string }) { const dispatch = useAppDispatch(); const cartCount = useAppSelector(selectCartCount); const { data: product, isLoading } = useGetProductsQuery({ id: productId }); if (isLoading) return <Skeleton />; return ( <div> <h3>{product.name}</h3> <button onClick={() => dispatch(addItem(product))}> Add to cart ({cartCount}) </button> </div> ); } 

Why choose Redux DevTools?

The Redux DevTools Extension lets you review all action history, travel to any previous state (time-travel), and export/import state for bug reproduction. In the configuration above, we enable it with action call tracing. This reduces bug-finding time by 30%.

What's included in the work?

  • Typed store with slices for each domain
  • RTK Query endpoints with full cache invalidation
  • Memoized selectors and re-render optimization
  • Redux DevTools integration with tracing
  • State architecture documentation and legacy code migration

Our team has over 5 years of production experience with Redux across projects of varying complexity — from e-commerce stores to control panels with hundreds of components. We guarantee a scalable and predictable architecture. Order Redux setup for your project — we'll analyze your current state and suggest a migration plan. Get a consultation on state management optimization — contact us, and we'll tailor an architecture to your scale.

Timeline estimates

Stage Duration
Store, slices, typed hooks setup 3-5 days
RTK Query endpoints and component integration 5-8 days
Memoized selectors, optimization, tests 4-6 days
Documentation, code review, DevTools 2-3 days

Reducer functions are tested in isolation without React — this is one of the main advantages of Redux architecture over hooks. Reach out to us for Redux setup — we'll bring order to your state management.