Instruction file imported from bradcstevens/github-copilot-agent-mode-starter-kit (
.github/instructions/technologies/ant-design.instructions.md). Copyright stays with the author.
Ant Design (antd) Best Practices and Coding Standards
This document outlines the recommended best practices for developing React applications using the Ant Design (antd) UI library. Following these guidelines will lead to more maintainable, performant, and secure applications.
1. Code Organization and Structure
1.1. Directory Structure
src/components/: Contains reusable React components, including those utilizing antd components.src/pages/: Contains components representing different application routes or pages.src/layouts/: Contains layout components that provide a consistent structure across pages.src/services/: Contains modules for interacting with APIs and handling data fetching.src/utils/: Contains utility functions and helper modules.src/styles/: Contains global styles, theme customizations, and component-specific stylesheets.src/assets/: Contains static assets such as images, fonts, and icons.src/context/: (Optional) If using context API, store all context definition files here.
Example:
my-app/
├── src/
│ ├── components/
│ │ ├── Button.jsx
│ │ ├── Input.jsx
│ │ └── ...
│ ├── pages/
│ │ ├── HomePage.jsx
│ │ ├── LoginPage.jsx
│ │ └── ...
│ ├── layouts/
│ │ ├── MainLayout.jsx
│ │ └── ...
│ ├── services/
│ │ ├── api.js
│ │ └── ...
│ ├── utils/
│ │ ├── date-formatter.js
│ │ └── ...
│ ├── styles/
│ │ ├── global.css
│ │ ├── theme.js
│ │ └── ...
│ ├── App.jsx
│ └── index.js
└── ...
1.2. File Naming Conventions
- Components: Use PascalCase for component file names (e.g.,
MyComponent.jsx,UserProfile.tsx). - Styles: Use kebab-case for style file names (e.g.,
my-component.css,user-profile.module.scss). - Modules: Use camelCase for module file names (e.g.,
api.js,dateFormatter.ts).
1.3. Module Organization
- Group related components, styles, and assets within the same directory.
- Create separate modules for API interactions, data transformations, and utility functions.
1.4. Component Architecture
- Presentational Components: Focus on rendering UI elements and receiving data via props.
- Container Components: Handle data fetching, state management, and logic, passing data to presentational components.
- Use functional components with hooks whenever possible for simplicity and reusability.
1.5. Code Splitting
- Utilize React.lazy and Suspense to load components on demand, improving initial load time.
- Split routes into separate chunks to minimize the initial bundle size.
- Consider using dynamic imports for less frequently used components or modules.
Example:
jsx import React, { Suspense } from 'react';
const MyComponent = React.lazy(() => import('./MyComponent'));
function MyPage() { return ( <Suspense fallback={Loading...}> ); }
2. Common Patterns and Anti-patterns
2.1. Design Patterns
- Higher-Order Components (HOCs): Use for cross-cutting concerns like authentication or data fetching. Prefer hooks where possible.
- Render Props: An alternative to HOCs for sharing code between components. Prefer hooks where possible.
- Compound Components: Create reusable components with implicit state sharing (e.g.,
TabsandTabcomponents).
2.2. Recommended Approaches
- Form Handling: Use
antd'sFormcomponent for managing form state, validation, and submission. - Data Display: Leverage
antd'sTable,List, andCardcomponents for structured data presentation. - Navigation: Use
antd'sMenuandBreadcrumbcomponents for creating intuitive navigation.
2.3. Anti-patterns and Code Smells
- Direct DOM Manipulation: Avoid directly manipulating the DOM; let React manage updates.
- Over-reliance on
anytype: Usinganyin TypeScript defeats the purpose of static typing. Provide explicit types. - Mutating Props: Treat props as read-only and avoid modifying them directly.
- Inline Styles: Keep styles in CSS files or use styled-components for better organization and maintainability. Prefer CSS Modules or Styled Components for component specific styles.
2.4. State Management
- Component State: Use
useStatefor simple, local component state. - Context API: Use for sharing state across multiple components without prop drilling.
- Redux/Zustand: Consider for complex applications with global state and predictable state transitions.
- MobX: Consider for complex applications where you want to observe changes in your data and derive calculations from that data.
2.5. Error Handling
- Try-Catch Blocks: Use for handling synchronous errors.
- Error Boundaries: Use to catch errors during rendering and prevent the entire application from crashing.
- Global Error Handling: Implement a global error handler to log errors and provide user feedback.
Example (Error Boundary):
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
console.error('Caught error: ', error, errorInfo);
}
render() {
if (this.state.hasError) {
return <h1>Something went wrong.</h1>;
}
return this.props.children;
}
}
export default ErrorBoundary;
// Usage:
<ErrorBoundary>
<MyComponent />
</ErrorBoundary>
3. Performance Considerations
3.1. Optimization Techniques
- Memoization: Use
React.memoto prevent unnecessary re-renders of components with the same props. - Pure Components: Extend
React.PureComponentfor class components to perform shallow prop comparisons. - Virtualization: Use
antd'sTableandListcomponents with virtualization for large datasets. - Debouncing/Throttling: Use for event handlers that trigger frequent updates (e.g., search input).
3.2. Memory Management
- Avoid Memory Leaks: Properly clean up event listeners and timers in
useEffecthooks. - Release Resources: Release unused objects and data structures to free up memory.
3.3. Rendering Optimization
- ShouldComponentUpdate: Implement
shouldComponentUpdate(for class components) or useReact.memo(for functional components) to prevent unnecessary re-renders. - Immutable Data: Use immutable data structures to simplify change detection.
3.4. Bundle Size Optimization
- Modular Imports: Import only the necessary components from
antdto reduce bundle size (e.g.,import { Button } from 'antd';). Usebabel-plugin-importfor automatic modular imports. - Tree Shaking: Ensure your build process supports tree shaking to remove unused code.
- Code Splitting: As mentioned earlier, split your code into smaller chunks to reduce the initial bundle size.
3.5. Lazy Loading
- Use
React.lazyandSuspenseto load components on demand. - Implement lazy loading for images and other assets using libraries like
react-lazyload.
4. Security Best Practices
4.1. Common Vulnerabilities
- Cross-Site Scripting (XSS): Prevent XSS by sanitizing user input and encoding output.
- Cross-Site Request Forgery (CSRF): Protect against CSRF attacks by implementing CSRF tokens.
- SQL Injection: Avoid directly embedding user input in SQL queries; use parameterized queries or ORMs.
4.2. Input Validation
- Server-Side Validation: Always validate user input on the server-side.
- Client-Side Validation: Use
antd'sFormcomponent for client-side validation to provide immediate feedback to the user. - Sanitize Input: Sanitize user input to remove potentially harmful characters or code.
4.3. Authentication and Authorization
- Secure Authentication: Use secure authentication mechanisms like JWT (JSON Web Tokens) or OAuth.
- Role-Based Access Control (RBAC): Implement RBAC to control access to different parts of the application based on user roles.
4.4. Data Protection
- Encryption: Encrypt sensitive data both in transit and at rest.
- Data Masking: Mask sensitive data in the UI to prevent unauthorized access.
4.5. Secure API Communication
- HTTPS: Use HTTPS to encrypt communication between the client and the server.
- API Rate Limiting: Implement rate limiting to prevent abuse and denial-of-service attacks.
5. Testing Approaches
5.1. Unit Testing
- Test individual components in isolation to ensure they function correctly.
- Use testing libraries like Jest and React Testing Library.
- Mock dependencies to isolate the component being tested.
5.2. Integration Testing
- Test the interaction between multiple components or modules.
- Use testing libraries like React Testing Library and Cypress.
5.3. End-to-End Testing
- Test the entire application from the user's perspective.
- Use testing frameworks like Cypress or Playwright.
5.4. Test Organization
- Create a
tests/directory at the root of your project. - Place test files alongside the components or modules they test (e.g.,
MyComponent.test.jsx). - Use descriptive test names to clearly indicate what is being tested.
5.5. Mocking and Stubbing
- Use mocking libraries like Jest's
jest.mock()to mock external dependencies. - Use stubbing to replace functions or methods with predefined behavior.
6. Common Pitfalls and Gotchas
6.1. Frequent Mistakes
- Not using modular imports: Importing the entire
antdlibrary can significantly increase bundle size. - Ignoring TypeScript errors: Failing to address TypeScript errors can lead to runtime issues.
- Not handling asynchronous operations correctly: Failing to handle promises or async/await can lead to unhandled rejections and unexpected behavior.
- Not localizing strings correctly: Hardcoding strings instead of using
antdi18n features.
6.2. Edge Cases
- Handling different screen sizes and devices: Ensuring responsive design using
antdgrid system. - Accessibility: Consider accessibility when using components, making sure to include
ariaattributes. - Browser compatibility: Test the app on various browsers (Chrome, Firefox, Safari, Edge, etc).
6.3. Version-Specific Issues
- Breaking changes: Be aware of breaking changes when upgrading
antdversions. - Deprecated APIs: Avoid using deprecated APIs and migrate to the recommended alternatives.
- CSS class conflicts: Potential issues with CSS specificity or conflicts with global styles. Use CSS Modules or Styled Components for more robust style isolation.
6.4. Compatibility Concerns
- React version: Ensure compatibility between
antdand your React version. - Other UI libraries: Avoid conflicts with other UI libraries by using consistent styling and naming conventions.
6.5. Debugging
- Use browser developer tools: Inspect the DOM, network requests, and console output.
- Use React DevTools: Inspect the component tree, props, and state.
- Use logging and debugging statements: Add
console.logstatements to trace the execution flow and inspect variable values.
7. Tooling and Environment
7.1. Recommended Tools
- IDE: VS Code, WebStorm.
- Build Tool: Webpack, Parcel, Rollup, esbuild.
- Testing Libraries: Jest, React Testing Library, Cypress.
- Linting: ESLint, Prettier.
7.2. Build Configuration
- Optimize for production: Use production-specific build configurations to minimize bundle size and improve performance.
- Configure code splitting: Set up code splitting to load components on demand.
- Enable tree shaking: Ensure your build process supports tree shaking to remove unused code.
7.3. Linting and Formatting
- ESLint: Use ESLint with recommended React and
antdplugins to enforce coding standards and detect potential errors. - Prettier: Use Prettier to automatically format your code for consistency.
- Stylelint: Use Stylelint to enforce consistent style practices.
7.4. Deployment
- Choose a hosting platform: Netlify, Vercel, AWS, Google Cloud, Azure.
- Configure environment variables: Set up environment variables for API keys, database credentials, and other sensitive information.
- Use a CDN: Use a Content Delivery Network (CDN) to cache static assets and improve loading times.
7.5. CI/CD Integration
- Set up a CI/CD pipeline: Use tools like Jenkins, Travis CI, CircleCI, or GitHub Actions to automate testing, building, and deployment.
- Automate testing: Run unit, integration, and end-to-end tests in your CI/CD pipeline.
- Automate deployment: Automate the deployment process to reduce manual effort and errors.