A modern React e-commerce application demonstrating data normalization patterns with RTK Query for server state management. This project showcases best practices for handling complex relational data in a React application.
- RTK Query Integration: Automatic caching, background refetching, and optimistic updates
- Data Normalization: Efficient handling of relational data (Products, Categories, Users, Reviews)
- Full CRUD Operations: Create, read, update, and delete products
- Real-time Updates: UI automatically reflects data changes
- TypeScript: Full type safety throughout the application
- Modern UI: Built with Tailwind CSS and Lucide React icons
- JSON Server: Simple REST API for development
- Entities: Separate stores for Products, Categories, Users, and Reviews
- Relationships: ID-based references between entities
- Selectors: Memoized selectors for combining normalized data
- Performance: Efficient updates and minimal re-renders
- API Slice: Centralized API definitions with automatic cache management
- Normalizers: Transform API responses into normalized data structures
- Optimistic Updates: Instant UI feedback for better UX
- Error Handling: Built-in loading states and error management
- React 19 - UI Framework
- TypeScript - Type Safety
- Redux Toolkit - State Management
- RTK Query - Server State Management
- Tailwind CSS - Styling
- Vite - Build Tool
- JSON Server - Mock REST API
- Lucide React - Icons
- Node.js 18+
- Yarn or npm
- Clone the repository
git clone https://github.com/chambits/data-normalization-redux-rtk-query.git
cd data-normalization-redux-rtk-query- Install dependencies
yarn install- Start development servers
Option 1: Separate terminals (Recommended)
# Terminal 1: Start JSON Server (API)
yarn dev:api
# Terminal 2: Start React App
yarn dev:appOption 2: Individual commands
# Start JSON Server on port 3001
yarn json-server
# In another terminal, start React app on port 5173
yarn devyarn dev- Start Vite dev server (React app)yarn dev:api- Start JSON Server on port 3001yarn dev:app- Start React app on port 5173yarn json-server- Start JSON Server with watch modeyarn build- Build for productionyarn preview- Preview production build
src/
├── components/ # React components
│ ├── Header.tsx # Navigation with add product
│ ├── ProductCard.tsx # Product display with edit/delete
│ ├── ProductForm.tsx # Create/edit product form
│ ├── ProductGrid.tsx # Product listing
│ ├── CategoryFilter.tsx # Category filtering
│ ├── ErrorMessage.tsx # Error handling UI
│ └── LoadingSpinner.tsx # Loading states
├── store/ # Redux store configuration
│ ├── api/ # RTK Query setup
│ │ ├── apiSlice.ts # API definitions
│ │ └── normalizers.ts # Data transformation
│ ├── slices/ # Entity slices
│ │ ├── productsSlice.ts
│ │ ├── categoriesSlice.ts
│ │ ├── usersSlice.ts
│ │ └── reviewsSlice.ts
│ ├── selectors.ts # Memoized selectors
│ └── store.ts # Store configuration
├── types/ # TypeScript definitions
│ ├── index.ts # Entity types
│ └── api.ts # API types
├── hooks/ # Custom React hooks
├── data/ # Mock data (for reference)
├── db.json # JSON Server database
└── App.tsx # Main application
// Normalized state structure
{
products: { 1: { id: 1, name: "...", categoryId: 1, reviewIds: [1, 2] } },
categories: { 1: { id: 1, name: "Electronics" } },
reviews: { 1: { id: 1, text: "...", authorId: 1, productId: 1 } },
users: { 1: { id: 1, name: "John Doe" } }
}// API slice with automatic normalization
const apiSlice = createApi({
baseQuery: fetchBaseQuery({ baseUrl: "http://localhost:3001" }),
endpoints: (builder) => ({
getProducts: builder.query({
query: () => "/products",
transformResponse: (response) => normalizeProductsResponse(response),
}),
}),
});// Combine normalized data efficiently
const selectProductWithDetails = createSelector(
[selectProductById, selectAllCategories, selectAllReviews, selectAllUsers],
(product, categories, reviews, users) => {
// Combine related data
}
);- Start both servers (see Development Setup above)
- Open
http://localhost:5173in your browser - View Products: Browse the product catalog with category filtering
- Add Product: Click "Add Product" in the header to create new products
- Edit Product: Click the menu (⋮) on any product card to edit
- Delete Product: Use the delete option in the product menu
- Real-time Updates: Changes are immediately reflected across the UI
- Data Persistence: All changes are saved to
db.json
Feel free to submit issues and pull requests to improve this example!
This project is for educational purposes and demonstrates modern React development patterns.