196 lines
11 KiB
Plaintext
196 lines
11 KiB
Plaintext
---
|
|
description: This rule provides comprehensive guidance on Redux best practices, covering code structure, performance optimization, testing strategies, and common pitfalls to ensure robust and maintainable Redux applications.
|
|
globs: *.js,*.jsx,*.ts,*.tsx
|
|
---
|
|
- **Introduction:** This document outlines best practices for developing applications with Redux, covering various aspects from code organization to performance optimization.
|
|
|
|
## 1. Code Organization and Structure:
|
|
|
|
- **Directory Structure:** Organize your Redux-related files in a clear and maintainable structure. A feature-based approach is recommended.
|
|
- Example:
|
|
|
|
src/
|
|
├── app/
|
|
│ ├── store.js # Redux store configuration
|
|
├── features/
|
|
│ ├── counter/ # Feature module (e.g., 'counter')
|
|
│ │ ├── counterSlice.js # Redux slice (reducers + actions)
|
|
│ │ ├── Counter.jsx # React component
|
|
│ │ ├── counterAPI.js # API interaction logic
|
|
│ │ └── counterSelectors.js # Selectors
|
|
│ ├── todos/
|
|
│ │ └── ...
|
|
├── components/ # Reusable UI components
|
|
├── utils/ # Utility functions
|
|
└── ...
|
|
|
|
|
|
- **File Naming Conventions:** Use consistent and descriptive names for your files.
|
|
- Example:
|
|
- `counterSlice.js` for Redux slice files
|
|
- `Counter.jsx` for React components
|
|
- `counterActions.js` or preferably included in slice
|
|
- `counterSelectors.js` for selectors
|
|
|
|
- **Module Organization:** Group related logic into modules. Each feature should have its own directory containing its Redux slice, components, and selectors.
|
|
|
|
- **Component Architecture:** Use a container/presentational component pattern to separate data fetching and state management logic from UI rendering.
|
|
- **Container Components:** Connect to the Redux store and pass data to presentational components.
|
|
- **Presentational Components:** Focus on UI rendering and receive data and callbacks as props.
|
|
|
|
- **Code Splitting Strategies:** Implement code splitting to reduce the initial bundle size and improve loading times.
|
|
- **Route-based splitting:** Load different parts of the application based on the current route.
|
|
- **Component-based splitting:** Lazy-load components that are not immediately needed.
|
|
- Use `React.lazy` and `<Suspense>` for component-based splitting.
|
|
|
|
## 2. Common Patterns and Anti-patterns:
|
|
|
|
- **Design Patterns:**
|
|
- **Flux Standard Actions (FSA):** A convention for structuring Redux actions with a `type` and an optional `payload` and `error` property.
|
|
- **Selectors:** Use selectors (e.g., with Reselect) to derive data from the Redux store efficiently.
|
|
- **Thunks/Sagas:** Manage asynchronous side effects using Redux Thunk or Redux Saga.
|
|
|
|
- **Recommended Approaches:**
|
|
- **Redux Toolkit:** Use Redux Toolkit to simplify Redux development and reduce boilerplate.
|
|
- **Immutability:** Treat state as immutable and use immutable data structures or techniques to update it.
|
|
- **Normalization:** Normalize your state to reduce data duplication and improve data consistency.
|
|
|
|
- **Anti-patterns and Code Smells:**
|
|
- **Mutating State Directly:** Never mutate state directly. Always create new copies of objects and arrays.
|
|
- **Putting too much logic in components:** Keep components focused on rendering. Move complex logic to reducers, selectors, or middleware.
|
|
- **Large Reducers:** Split large reducers into smaller, more manageable reducers using `combineReducers`.
|
|
- **Over-fetching Data:** Fetch only the data that is needed by the component. Use selectors to derive specific data subsets from the state.
|
|
|
|
- **State Management Best Practices:**
|
|
- **Single Source of Truth:** Keep all application state in the Redux store.
|
|
- **Predictable State Updates:** Ensure that state updates are predictable and deterministic.
|
|
- **Minimize Global State:** Only store data that is truly global in the Redux store. Local component state should be used for UI-specific data.
|
|
|
|
- **Error Handling Patterns:**
|
|
- **Action-based Error Handling:** Dispatch actions to indicate errors and update the state accordingly.
|
|
- **Middleware Error Handling:** Use middleware to catch errors and log them to a central error reporting service.
|
|
|
|
## 3. Performance Considerations:
|
|
|
|
- **Optimization Techniques:**
|
|
- **Memoization:** Use memoization to avoid unnecessary re-renders. Use `React.memo` for functional components and `shouldComponentUpdate` for class components.
|
|
- **Selectors:** Use selectors with memoization (e.g., Reselect) to avoid recomputing derived data when the input state hasn't changed.
|
|
- **Batch Updates:** Batch multiple state updates into a single update to reduce the number of re-renders.
|
|
- **Debouncing/Throttling:** Use debouncing or throttling to limit the frequency of updates.
|
|
|
|
- **Memory Management:**
|
|
- **Avoid Memory Leaks:** Clean up event listeners and timers when components unmount.
|
|
- **Optimize Data Structures:** Use efficient data structures to reduce memory usage.
|
|
|
|
- **Rendering Optimization:**
|
|
- **Virtualization:** Use virtualization for large lists to only render the visible items.
|
|
- **Code Splitting:** Reduce the initial bundle size by splitting the code into smaller chunks.
|
|
|
|
- **Bundle Size Optimization:**
|
|
- **Tree Shaking:** Remove unused code from the bundle using tree shaking.
|
|
- **Minification:** Minify the code to reduce the bundle size.
|
|
- **Compression:** Compress the bundle using Gzip or Brotli.
|
|
|
|
- **Lazy Loading Strategies:**
|
|
- **Route-based Lazy Loading:** Load different routes on demand.
|
|
- **Component-based Lazy Loading:** Load components on demand using `React.lazy`.
|
|
|
|
## 4. Security Best Practices:
|
|
|
|
- **Common Vulnerabilities:**
|
|
- **Cross-Site Scripting (XSS):** Prevent XSS attacks by sanitizing user inputs and escaping outputs.
|
|
- **Cross-Site Request Forgery (CSRF):** Protect against CSRF attacks by using anti-CSRF tokens.
|
|
- **Data Injection:** Prevent data injection attacks by validating and sanitizing inputs.
|
|
|
|
- **Input Validation:**
|
|
- **Client-Side Validation:** Validate inputs on the client-side to provide immediate feedback to the user.
|
|
- **Server-Side Validation:** Validate inputs on the server-side to ensure data integrity.
|
|
|
|
- **Authentication and Authorization Patterns:**
|
|
- **JWT (JSON Web Tokens):** Use JWTs for authentication and authorization.
|
|
- **Role-Based Access Control (RBAC):** Implement RBAC to control access to different parts of the application.
|
|
|
|
- **Data Protection Strategies:**
|
|
- **Encryption:** Encrypt sensitive data at rest and in transit.
|
|
- **Data Masking:** Mask sensitive data to protect it from unauthorized access.
|
|
|
|
- **Secure API Communication:**
|
|
- **HTTPS:** Use HTTPS to encrypt communication between the client and the server.
|
|
- **API Rate Limiting:** Implement API rate limiting to prevent abuse.
|
|
|
|
## 5. Testing Approaches:
|
|
|
|
- **Unit Testing Strategies:**
|
|
- **Test Reducers:** Test reducers to ensure that they update the state correctly.
|
|
- **Test Actions:** Test actions to ensure that they dispatch the correct payloads.
|
|
- **Test Selectors:** Test selectors to ensure that they derive the correct data from the state.
|
|
|
|
- **Integration Testing:**
|
|
- **Test Components:** Test components to ensure that they render correctly and interact with the Redux store.
|
|
- **Test Middleware:** Test middleware to ensure that they handle side effects correctly.
|
|
|
|
- **End-to-end Testing:**
|
|
- **Test User Flows:** Test user flows to ensure that the application works as expected from the user's perspective.
|
|
|
|
- **Test Organization:**
|
|
- **Test Directory Structure:** Organize tests in a clear and maintainable structure.
|
|
- Example:
|
|
|
|
src/
|
|
├── features/
|
|
│ ├── counter/
|
|
│ │ ├── counterSlice.test.js
|
|
│ │ ├── Counter.test.jsx
|
|
|
|
|
|
- **Mocking and Stubbing:**
|
|
- **Mock API Calls:** Mock API calls to isolate components and reducers during testing.
|
|
- **Stub Dependencies:** Stub external dependencies to control their behavior during testing.
|
|
|
|
## 6. Common Pitfalls and Gotchas:
|
|
|
|
- **Frequent Mistakes:**
|
|
- **Forgetting to Return State:** Reducers must always return the new state. If no change, return the original state.
|
|
- **Incorrectly Updating Nested Objects:** Remember to create copies of all levels when updating nested objects.
|
|
- **Not Handling Asynchronous Actions Correctly:** Using thunks or sagas incorrectly can lead to unexpected behavior.
|
|
|
|
- **Edge Cases:**
|
|
- **Initial State:** Ensure that the initial state is correctly defined.
|
|
- **Handling Errors:** Handle errors gracefully and provide informative error messages.
|
|
- **Empty States:** Handle empty states correctly to avoid unexpected behavior.
|
|
|
|
- **Version-Specific Issues:**
|
|
- **React Redux v8 vs v7:** Be aware of the changes introduced in React Redux v8, such as the improved performance and the new `useSyncExternalStore` hook.
|
|
|
|
- **Compatibility Concerns:**
|
|
- **Browser Compatibility:** Ensure that the application works correctly in all supported browsers.
|
|
- **Device Compatibility:** Ensure that the application works correctly on all supported devices.
|
|
|
|
- **Debugging Strategies:**
|
|
- **Redux DevTools:** Use the Redux DevTools extension to inspect the state and track actions.
|
|
- **Console Logging:** Use console logging to debug code and track state changes.
|
|
- **Debugging Tools:** Use browser debugging tools to step through code and inspect variables.
|
|
|
|
## 7. Tooling and Environment:
|
|
|
|
- **Recommended Development Tools:**
|
|
- **Redux DevTools Extension:** Inspect Redux state and actions.
|
|
- **VS Code with Redux Extension:** Provides code completion, linting, and debugging support for Redux.
|
|
|
|
- **Build Configuration:**
|
|
- **Webpack/Parcel/Rollup:** Use a module bundler to bundle the code and optimize it for production.
|
|
- **Babel:** Use Babel to transpile the code to older versions of JavaScript.
|
|
|
|
- **Linting and Formatting:**
|
|
- **ESLint:** Use ESLint to enforce code style and prevent errors.
|
|
- **Prettier:** Use Prettier to automatically format the code.
|
|
|
|
- **Deployment Best Practices:**
|
|
- **Environment Variables:** Use environment variables to configure the application for different environments.
|
|
- **CDN:** Use a CDN to serve static assets.
|
|
|
|
- **CI/CD Integration:**
|
|
- **Automated Testing:** Run tests automatically as part of the CI/CD pipeline.
|
|
- **Automated Deployment:** Deploy the application automatically to different environments.
|
|
|
|
This comprehensive guide should help you build robust, maintainable, and performant Redux applications. Remember to stay up-to-date with the latest best practices and tools in the Redux ecosystem. |