expo
exporeacttypescriptstate-managementperformance
Description
This rule provides comprehensive best practices and coding standards for Expo projects, covering code organization, performance, security, testing, and common pitfalls to ensure maintainable and high-quality applications.
Globs
**/*.{js,jsx,ts,tsx}
---
description: This rule provides comprehensive best practices and coding standards for Expo projects, covering code organization, performance, security, testing, and common pitfalls to ensure maintainable and high-quality applications.
globs: **/*.{js,jsx,ts,tsx}
---
- **Code Organization and Structure**
- **Directory Structure:**
- Adopt a feature-based directory structure, grouping related files (components, hooks, styles, tests) within feature folders.
- Examples:
src/
├── components/
│ ├── Button/
│ │ ├── Button.tsx
│ │ ├── Button.styles.ts
│ │ └── Button.test.tsx
│ └── ...
├── screens/
│ ├── Home/
│ │ ├── HomeScreen.tsx
│ │ ├── HomeScreen.styles.ts
│ │ └── HomeScreen.test.tsx
│ └── ...
├── navigation/
│ ├── AppNavigator.tsx
│ └── ...
├── services/
│ ├── api.ts
│ └── ...
├── utils/
│ ├── helpers.ts
│ └── ...
├── App.tsx
└── index.tsx
- **File Naming Conventions:**
- Use descriptive and consistent names for files and directories.
- Component files: `ComponentName.tsx` or `ComponentName.js`
- Style files: `ComponentName.styles.ts` or `ComponentName.styles.js`
- Hook files: `useHookName.ts` or `useHookName.js`
- Test files: `ComponentName.test.tsx` or `ComponentName.test.js`
- **Module Organization:**
- Group related components, hooks, and utilities into modules.
- Use `index.ts` (or `index.js`) files to export members from a module for easier importing.
- Example:
// src/components/Button/index.ts
export { default as Button } from './Button';
- **Component Architecture:**
- Favor functional components with hooks for managing state and side effects.
- Separate concerns by creating presentational (UI) and container (logic) components.
- Use component composition to build complex UIs from smaller, reusable components.
- **Code Splitting Strategies:**
- Implement lazy loading for screens or components that are not immediately needed.
- Utilize `React.lazy` and `Suspense` for dynamic imports.
- Expo supports dynamic imports; leverage them to reduce initial bundle size.
- **Common Patterns and Anti-patterns**
- **Design Patterns:**
- **Higher-Order Components (HOCs):** Use cautiously; prefer hooks or render props for better composability.
- **Render Props:** A pattern for sharing code between React components using a prop whose value is a function.
- **Compound Components:** Create components that implicitly share state (e.g., Tabs and Tab).
- **Recommended Approaches:**
- Use Expo's APIs for accessing device features (camera, location, notifications) instead of relying on native modules directly where possible.
- Leverage Expo's managed workflow for a smoother development experience.
- **Anti-patterns:**
- Directly manipulating the DOM (use React's state and props instead).
- Writing complex logic directly within components (extract into hooks or utility functions).
- Neglecting error handling and edge cases.
- **State Management:**
- Use React Context for simple state management.
- Consider libraries like Zustand, Redux, or Jotai for more complex state management needs.
- Leverage `useReducer` for managing complex state transitions.
- **Error Handling:**
- Implement try-catch blocks to handle potential errors.
- Use error boundary components to catch errors during rendering.
- Log errors using a centralized logging service (e.g., Sentry).
- **Performance Considerations**
- **Optimization Techniques:**
- Use `React.memo` to prevent unnecessary re-renders of components.
- Implement `shouldComponentUpdate` (for class components) or `useMemo` and `useCallback` (for functional components) to optimize rendering.
- Debounce or throttle event handlers to reduce the frequency of updates.
- **Memory Management:**
- Avoid creating large arrays or objects in component state if not necessary.
- Clean up event listeners and timers when components unmount.
- Release resources when they are no longer needed.
- **Rendering Optimization:**
- Virtualize long lists using `FlatList` or `SectionList` to improve scrolling performance.
- Optimize image sizes and formats to reduce loading times.
- Use the `useNativeDriver: true` prop in animations for better performance.
- **Bundle Size Optimization:**
- Use code splitting to reduce the initial bundle size.
- Remove unused code and dependencies.
- Optimize images and other assets.
- **Lazy Loading:**
- Implement lazy loading for images and other resources that are not immediately visible.
- Use the `<Image>` component from `react-native` or `expo-image` with placeholder and loading indicators.
- **Security Best Practices**
- **Common Vulnerabilities:**
- Cross-Site Scripting (XSS) - Not typically a risk in React Native/Expo, but be mindful when rendering user-provided content via WebView.
- Data injection - Protect against SQL or command injection if interacting with backend systems.
- Insecure data storage - Never store sensitive information (API keys, credentials) directly in the app code.
- **Input Validation:**
- Validate user input on both the client and server sides.
- Use appropriate data types and formats.
- Sanitize user input to prevent injection attacks.
- **Authentication and Authorization:**
- Use secure authentication mechanisms (e.g., OAuth 2.0, JWT).
- Implement proper authorization to restrict access to sensitive data and functionality.
- Store authentication tokens securely (e.g., using Expo SecureStore).
- **Data Protection:**
- Encrypt sensitive data at rest and in transit.
- Use HTTPS for all API communication.
- Avoid storing sensitive information in logs.
- **Secure API Communication:**
- Use HTTPS for all API requests.
- Validate API responses.
- Implement rate limiting to prevent abuse.
- **Testing Approaches**
- **Unit Testing:**
- Write unit tests for individual components, hooks, and utility functions.
- Use testing libraries like Jest and React Testing Library.
- Mock dependencies to isolate units of code.
- **Integration Testing:**
- Test the interactions between multiple components or modules.
- Use tools like Detox or Appium for end-to-end testing on real devices or emulators.
- **End-to-end Testing:**
- Simulate user interactions to test the entire application flow.
- Use tools like Detox or Appium for end-to-end testing on real devices or emulators.
- **Test Organization:**
- Organize tests in a clear and maintainable structure.
- Group tests by component or module.
- Use descriptive names for test cases.
- **Mocking and Stubbing:**
- Use mocking to isolate units of code and simulate dependencies.
- Use stubbing to replace complex or external dependencies with simplified versions.
- **Common Pitfalls and Gotchas**
- **Frequent Mistakes:**
- Forgetting to clean up event listeners or timers.
- Mutating state directly instead of using `setState` or state update functions.
- Over-rendering components due to unnecessary state updates.
- **Edge Cases:**
- Handling different screen sizes and orientations.
- Dealing with slow network connections or API failures.
- Managing application state during interruptions (e.g., phone calls).
- **Version-specific Issues:**
- Be aware of breaking changes in React Native and Expo SDK updates.
- Test your application thoroughly after upgrading dependencies.
- **Compatibility Concerns:**
- Test your application on different devices and operating systems.
- Use platform-specific code only when necessary.
- **Debugging Strategies:**
- Use the React Native debugger or Chrome DevTools for debugging.
- Use console.log statements or debugging tools to inspect variables and application state.
- Use error boundary components to catch and log errors.
- **Tooling and Environment**
- **Recommended Tools:**
- VS Code with Expo and ESLint extensions
- Expo CLI for managing Expo projects.
- React Native Debugger or Chrome DevTools for debugging.
- **Build Configuration:**
- Use environment variables to configure different build environments (development, staging, production).
- Configure your build process to optimize assets and reduce bundle size.
- **Linting and Formatting:**
- Use ESLint with the Airbnb or Standard style guide.
- Use Prettier to automatically format your code.
- Configure your editor to automatically run ESLint and Prettier on save.
- **Deployment:**
- Use Expo Application Services (EAS) for building and deploying your application.
- Follow Expo's deployment documentation for best practices.
- **CI/CD Integration:**
- Integrate your application with a CI/CD pipeline (e.g., GitHub Actions, CircleCI).
- Automate testing, linting, and deployment processes.
- **Expo Specific Recommendations**
- **Use Expo Modules:** Prefer Expo modules for accessing native features over community libraries when available, as they are guaranteed to be compatible and well-maintained within the Expo ecosystem.
- **EAS Build:** Use Expo Application Services (EAS) for building native binaries. This simplifies the build process and handles much of the complexity of native builds.
- **Expo Updates:** Implement Expo Updates for over-the-air updates. This allows for quicker iteration and bug fixes without requiring users to download a new version from the app store.
- **Managed Workflow:** Stick to the managed workflow whenever possible. It handles much of the native configuration and simplifies development.
- **Expo SecureStore:** Use `expo-secure-store` to securely store sensitive data like API keys and tokens.
- **Environment Variables:** Use `.env` files and `expo-constants` to manage environment-specific configurations.
- **Asset Management:** Place assets (images, fonts) in the `assets` folder and use the `Image` and `Font` components to load them.
- **TypeScript Best Practices**
- **Strict Mode:** Enable TypeScript's strict mode (`strict: true` in `tsconfig.json`) for enhanced type safety.
- **Explicit Types:** Explicitly define types for function parameters, return values, and variables.
- **Interfaces vs. Types:** Use interfaces for defining contract between objects, and types for defining data structures.
- **Utility Types:** Leverage TypeScript's utility types (e.g., `Partial`, `Required`, `Readonly`, `Pick`, `Omit`) for more concise and maintainable code.
- **Type Guards:** Use type guards to narrow down types within conditional blocks.
- **Async/Await:** Use `async/await` for asynchronous operations to improve code readability and avoid callback hell.
- **Resources**
- Expo Documentation: [https://docs.expo.dev/](https://docs.expo.dev/)
- React Native Documentation: [https://reactnative.dev/](https://reactnative.dev/)
- Expo JavaScript Style Guide: [https://github.com/expo/expo/blob/main/guides/Expo%20JavaScript%20Style%20Guide.md](https://github.com/expo/expo/blob/main/guides/Expo%20JavaScript%20Style%20Guide.md)