9.8 KiB
9.8 KiB
| 1 | No | Category | Guideline | Description | Do | Don't | Code Good | Code Bad | Severity | Docs URL |
|---|---|---|---|---|---|---|---|---|---|---|
| 2 | 1 | Components | Use functional components | Hooks-based components are standard | Functional components with hooks | Class components | const App = () => { } | class App extends Component | Medium | https://reactnative.dev/docs/intro-react |
| 3 | 2 | Components | Keep components small | Single responsibility principle | Split into smaller components | Large monolithic components | <Header /><Content /><Footer /> | 500+ line component | Medium | |
| 4 | 3 | Components | Use TypeScript | Type safety for props and state | TypeScript for new projects | JavaScript without types | const Button: FC<Props> = () => { } | const Button = (props) => { } | Medium | |
| 5 | 4 | Components | Colocate component files | Keep related files together | Component folder with styles | Flat structure | components/Button/index.tsx styles.ts | components/Button.tsx styles/button.ts | Low | |
| 6 | 5 | Styling | Use StyleSheet.create | Optimized style objects | StyleSheet for all styles | Inline style objects | StyleSheet.create({ container: {} }) | style={{ margin: 10 }} | High | https://reactnative.dev/docs/stylesheet |
| 7 | 6 | Styling | Avoid inline styles | Prevent object recreation | Styles in StyleSheet | Inline style objects in render | style={styles.container} | style={{ margin: 10, padding: 5 }} | Medium | |
| 8 | 7 | Styling | Use flexbox for layout | React Native uses flexbox | flexDirection alignItems justifyContent | Absolute positioning everywhere | flexDirection: 'row' | position: 'absolute' everywhere | Medium | https://reactnative.dev/docs/flexbox |
| 9 | 8 | Styling | Handle platform differences | Platform-specific styles | Platform.select or .ios/.android files | Same styles for both platforms | Platform.select({ ios: {}, android: {} }) | Hardcoded iOS values | Medium | https://reactnative.dev/docs/platform-specific-code |
| 10 | 9 | Styling | Use responsive dimensions | Scale for different screens | Dimensions or useWindowDimensions | Fixed pixel values | useWindowDimensions() | width: 375 | Medium | |
| 11 | 10 | Navigation | Use React Navigation | Standard navigation library | React Navigation for routing | Manual navigation management | createStackNavigator() | Custom navigation state | Medium | https://reactnavigation.org/ |
| 12 | 11 | Navigation | Type navigation params | Type-safe navigation | Typed navigation props | Untyped navigation | navigation.navigate<RootStackParamList>('Home', { id }) | navigation.navigate('Home', { id }) | Medium | |
| 13 | 12 | Navigation | Use deep linking | Support URL-based navigation | Configure linking prop | No deep link support | linking: { prefixes: [] } | No linking configuration | Medium | https://reactnavigation.org/docs/deep-linking/ |
| 14 | 13 | Navigation | Handle back button | Android back button handling | useFocusEffect with BackHandler | Ignore back button | BackHandler.addEventListener | No back handler | High | |
| 15 | 14 | State | Use useState for local state | Simple component state | useState for UI state | Class component state | const [count, setCount] = useState(0) | this.state = { count: 0 } | Medium | |
| 16 | 15 | State | Use useReducer for complex state | Complex state logic | useReducer for related state | Multiple useState for related values | useReducer(reducer initialState) | 5+ useState calls | Medium | |
| 17 | 16 | State | Use context sparingly | Context for global state | Context for theme auth locale | Context for frequently changing data | ThemeContext for app theme | Context for list item data | Medium | |
| 18 | 17 | State | Consider Zustand or Redux | External state management | Zustand for simple Redux for complex | useState for global state | create((set) => ({ })) | Prop drilling global state | Medium | |
| 19 | 18 | Lists | Use FlatList for long lists | Virtualized list rendering | FlatList for 50+ items | ScrollView with map | <FlatList data={items} /> | <ScrollView>{items.map()}</ScrollView> | High | https://reactnative.dev/docs/flatlist |
| 20 | 19 | Lists | Provide keyExtractor | Unique keys for list items | keyExtractor with stable ID | Index as key | keyExtractor={(item) => item.id} | keyExtractor={(_, index) => index} | High | |
| 21 | 20 | Lists | Optimize renderItem | Memoize list item components | React.memo for list items | Inline render function | renderItem={({ item }) => <MemoizedItem item={item} />} | renderItem={({ item }) => <View>...</View>} | High | |
| 22 | 21 | Lists | Use getItemLayout for fixed height | Skip measurement for performance | getItemLayout when height known | Dynamic measurement for fixed items | getItemLayout={(_, index) => ({ length: 50, offset: 50 * index, index })} | No getItemLayout for fixed height | Medium | |
| 23 | 22 | Lists | Implement windowSize | Control render window | Smaller windowSize for memory | Default windowSize for large lists | windowSize={5} | windowSize={21} for huge lists | Medium | |
| 24 | 23 | Performance | Use React.memo | Prevent unnecessary re-renders | memo for pure components | No memoization | export default memo(MyComponent) | export default MyComponent | Medium | |
| 25 | 24 | Performance | Use useCallback for handlers | Stable function references | useCallback for props | New function on every render | useCallback(() => {}, [deps]) | () => handlePress() | Medium | |
| 26 | 25 | Performance | Use useMemo for expensive ops | Cache expensive calculations | useMemo for heavy computations | Recalculate every render | useMemo(() => expensive(), [deps]) | const result = expensive() | Medium | |
| 27 | 26 | Performance | Avoid anonymous functions in JSX | Prevent re-renders | Named handlers or useCallback | Inline arrow functions | onPress={handlePress} | onPress={() => doSomething()} | Medium | |
| 28 | 27 | Performance | Use Hermes engine | Improved startup and memory | Enable Hermes in build | JavaScriptCore for new projects | hermes_enabled: true | hermes_enabled: false | Medium | https://reactnative.dev/docs/hermes |
| 29 | 28 | Images | Use expo-image | Modern performant image component for React Native | Use expo-image for caching, blurring, and performance | Use default Image for heavy lists or unmaintained libraries | <Image source={url} cachePolicy='memory-disk' /> (expo-image) | <FastImage source={url} /> | Medium | https://docs.expo.dev/versions/latest/sdk/image/ |
| 30 | 29 | Images | Specify image dimensions | Prevent layout shifts | width and height for remote images | No dimensions for network images | <Image style={{ width: 100 height: 100 }} /> | <Image source={{ uri }} /> no size | High | |
| 31 | 30 | Images | Use resizeMode | Control image scaling | resizeMode cover contain | Stretch images | resizeMode="cover" | No resizeMode | Low | |
| 32 | 31 | Forms | Use controlled inputs | State-controlled form fields | value + onChangeText | Uncontrolled inputs | <TextInput value={text} onChangeText={setText} /> | <TextInput defaultValue={text} /> | Medium | |
| 33 | 32 | Forms | Handle keyboard | Manage keyboard visibility | KeyboardAvoidingView | Content hidden by keyboard | <KeyboardAvoidingView behavior="padding"> | No keyboard handling | High | https://reactnative.dev/docs/keyboardavoidingview |
| 34 | 33 | Forms | Use proper keyboard types | Appropriate keyboard for input | keyboardType for input type | Default keyboard for all | keyboardType="email-address" | keyboardType="default" for email | Low | |
| 35 | 34 | Touch | Use Pressable | Modern touch handling | Pressable for touch interactions | TouchableOpacity for new code | <Pressable onPress={} /> | <TouchableOpacity onPress={} /> | Low | https://reactnative.dev/docs/pressable |
| 36 | 35 | Touch | Provide touch feedback | Visual feedback on press | Ripple or opacity change | No feedback on press | android_ripple={{ color: 'gray' }} | No press feedback | Medium | |
| 37 | 36 | Touch | Set hitSlop for small targets | Increase touch area | hitSlop for icons and small buttons | Tiny touch targets | hitSlop={{ top: 10 bottom: 10 }} | 44x44 with no hitSlop | Medium | |
| 38 | 37 | Animation | Use Reanimated | High-performance animations | react-native-reanimated | Animated API for complex | useSharedValue useAnimatedStyle | Animated.timing for gesture | Medium | https://docs.swmansion.com/react-native-reanimated/ |
| 39 | 38 | Animation | Run on UI thread | worklets for smooth animation | Run animations on UI thread | JS thread animations | runOnUI(() => {}) | Animated on JS thread | High | |
| 40 | 39 | Animation | Use gesture handler | Native gesture recognition | react-native-gesture-handler | JS-based gesture handling | <GestureDetector> | <View onTouchMove={} /> | Medium | https://docs.swmansion.com/react-native-gesture-handler/ |
| 41 | 40 | Async | Handle loading states | Show loading indicators | ActivityIndicator during load | Empty screen during load | {isLoading ? <ActivityIndicator /> : <Content />} | No loading state | Medium | |
| 42 | 41 | Async | Handle errors gracefully | Error boundaries and fallbacks | Error UI for failed requests | Crash on error | {error ? <ErrorView /> : <Content />} | No error handling | High | |
| 43 | 42 | Async | Cancel async operations | Cleanup on unmount | AbortController or cleanup | Memory leaks from async | useEffect cleanup | No cleanup for subscriptions | High | |
| 44 | 43 | Accessibility | Add accessibility labels | Describe UI elements | accessibilityLabel for all interactive | Missing labels | accessibilityLabel="Submit form" | <Pressable> without label | High | https://reactnative.dev/docs/accessibility |
| 45 | 44 | Accessibility | Use accessibility roles | Semantic meaning | accessibilityRole for elements | Wrong roles | accessibilityRole="button" | No role for button | Medium | |
| 46 | 45 | Accessibility | Support screen readers | Test with TalkBack/VoiceOver | Test with screen readers | Skip accessibility testing | Regular TalkBack testing | No screen reader testing | High | |
| 47 | 46 | Testing | Use React Native Testing Library | Component testing | render and fireEvent | Enzyme or manual testing | render(<Component />) | shallow(<Component />) | Medium | https://callstack.github.io/react-native-testing-library/ |
| 48 | 47 | Testing | Test on real devices | Real device behavior | Test on iOS and Android devices | Simulator only | Device testing in CI | Simulator only testing | High | |
| 49 | 48 | Testing | Use Detox for E2E | End-to-end testing | Detox for critical flows | Manual E2E testing | detox test | Manual testing only | Medium | https://wix.github.io/Detox/ |
| 50 | 49 | Native | Use native modules carefully | Bridge has overhead | Batch native calls | Frequent bridge crossing | Batch updates | Call native on every keystroke | High | |
| 51 | 50 | Native | Use Expo when possible | Simplified development | Expo for standard features | Bare RN for simple apps | expo install package | react-native link package | Low | https://docs.expo.dev/ |
| 52 | 51 | Native | Handle permissions | Request permissions properly | Check and request permissions | Assume permissions granted | PermissionsAndroid.request() | Access without permission check | High | https://reactnative.dev/docs/permissionsandroid |