--- 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 `` 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.