+1

React Native Best Practices không thể bỏ qua

Dành cho những người mới làm quen hoặc đã có kinh nghiệm với React Native, việc tuân thủ các phương pháp lập trình tốt là điều bắt buộc phải thực hiện. Bài viết này sẽ cung cấp những thông tin cần thiết về cách thức tổ chức mã nguồn, cũng như cách xử lý các vấn đề liên quan đến phát triển ứng dụng với React Native.

Trước khi chúng ta bắt đầu, các best practices trong bài viết này có thể được áp dụng trên React Native CLI hoặc dự án Expo. Từ năm 2024, theo nhóm React Native, Expo sẽ trở thành framework chính thức dùng để xây dựng các dự án React Native.

Trong bài viết này, chúng ta sẽ tìm hiểu về các phương pháp lập trình cho các dự án React Native. Hãy nhớ rằng một dự án tốt là sự cân bằng giữa:

  1. Khả năng mở rộng
  2. Tính nhất quán
  3. Dễ bảo trì
  4. Dễ đọc

Cấu trúc dự án

Điều đầu tiên của một nhà phát triển là phải có một cơ sở mã nguồn có thể bảo trì, dễ đọc và có khả năng mở rộng. Cấu trúc dự án của bạn sẽ giúp ích cho các nhà phát triển trong tương lai. Với Expo, người ta có cấu trúc của dự án nhưng với tư cách là một nhà phát triển React Native và dựa trên dự án của bạn, bạn nên lên kế hoạch cho cấu trúc dự án của mình:

my-app/
├── assets/
│   ├── fonts/
│   ├── images/
│   └── icons/
├── components/
│   ├── Button.js
│   ├── Button.styles.js
│   └── Header.js
├── screens/
│   ├── HomeScreen/
│   │   ├── HomeScreen.js
│   │   └── HomeScreen.styles.js
│   └── ProfileScreen/
│       ├── ProfileScreen.js
│       └── ProfileScreen.styles.js
├── navigation/
│   ├── AppNavigator.js
│   ├── AuthNavigator.js
│   └── MainNavigator.js
├── redux/ (or store/ if using Zustand, MobX, etc.)
│   ├── actions/
│   ├── reducers/
│   ├── store.js
│   └── types.js
├── services/
│   ├── api.js
│   └── auth.js
├── utils/
│   ├── helpers.js
│   └── constants.js
├── App.js
├── package.json
├── .babelrc
└── README.md

Hãy nhớ rằng, tùy theo yêu cầu của bạn, hãy khám phá kiến trúc cụ thể cho lĩnh vực hoặc tính năng.

Sử dụng bí danh cho Imports

Đường imports quá dài có thể khiến mã nguồn của bạn khó đọc và khó bảo trì hơn. Thay vì viết đường dẫn tương đối dài như ../../../components/Button, hãy sử dụng bí danh để rút ngắn chúng và làm cho mã nguồn của bạn dễ đọc hơn.

import Button from 'components/ui/Button';
import Header from 'components/layout/Header';

Thứ tự của Imports

Để tự động quản lý thứ tự của các lệnh nhập, bạn có thể cấu hình Babel với một plugin xử lý điều này cho bạn. Điều này giữ cho các lệnh nhập của bạn được sạch sẽ và giảm bớt can thiệp thủ công.

npm install --save-dev babel-plugin-module-resolver

TypeScript

Hầu như không có cuộc tranh cãi nào khi lựa chọn giữa TypeScript (TS) và JavaScript (JS), đặc biệt là đối với các ứng dụng quy mô lớn. TypeScript cung cấp kiểm tra kiểu tĩnh, giúp phát hiện lỗi tại thời điểm biên dịch thay vì thời gian chạy, dẫn đến mã nguồn tin cậy và dễ bảo trì hơn.

Style

Có nhiều cách mà một người có thể định dạng style cho các dự án React Native của họ. Một người có thể sử dụng NativeWind, hoặc style từ React native. Với nhiều lựa chọn như vậy, bạn nên chọn lựa sự nhất quán, khả năng mở rộng, và dễ bảo trì. Sau đây là chi tiết về cách sử dụng style:

1. inline

Đây không phải là cách tiếp cận tốt cho các dự án quy mô lớn.

<View style={{ backgroundColor: 'blue', padding: 10 }}>
  <Text style={{ color: 'white' }}>Hello</Text>
</View>

2. StyleSheet API

Tốt nhưng mà các style này sẽ không thể tái sử dụng.

import { StyleSheet, View, Text } from 'react-native';

const styles = StyleSheet.create({
  container: {
    backgroundColor: 'blue',
    padding: 10,
  },
  text: {
    color: 'white',
  },
});

const App = () => (
  <View style={styles.container}>
    <Text style={styles.text}>Hello</Text>
  </View>
);

3. Style riêng biệt

Đây là cách mà tôi ưa thích sử dụng đối với các dự án lớn. Tạo một style.js riêng biệt và sử dụng nó trong các thành phần mà bạn cần.

/components
   ├── MyComponent.js
   ├── MyComponent.styles.js
/App.js
// MyComponent.styles.js
import { StyleSheet } from 'react-native';

export default StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#f5f5f5',
  },
  title: {
    fontSize: 24,
    fontWeight: 'bold',
    color: '#333',
    marginBottom: 20,
  },
  button: {
    backgroundColor: '#007bff',
    paddingVertical: 10,
    paddingHorizontal: 20,
    borderRadius: 5,
  },
  buttonText: {
    color: '#fff',
    fontSize: 16,
    fontWeight: '600',
  },
});
// MyComponent.js
import React from 'react';
import { View, Text, Pressable } from 'react-native';
import styles from './MyComponent.styles';

const MyComponent = () => {
  return (
    <View style={styles.container}>
      <Text style={styles.title}>Hello from MyComponent</Text>
      <Pressable style={styles.button}>
        <Text style={styles.buttonText}>Click Me</Text>
      </Pressable>
    </View>
  );
};

export default MyComponent;

4. Native wind

NativeWind là một cách tốt để định dạng style cho ứng dụng của bạn. Sau khi cài đặt native wind, bạn có thể sử dụng các lớp để định dạng style cho ứng dụng của bạn. Bằng cách này, bạn đang phân công rõ ràng việc định dạng style.

import React from 'react';
import { View, Text, Pressable } from 'react-native';
import { styled } from 'nativewind';

const App = () => {
  return (
    <View className="flex-1 justify-center items-center bg-gray-100">
      <Text className="text-2xl font-bold text-blue-500 mb-4">
        Welcome to NativeWind!
      </Text>
      <Pressable className="bg-blue-500 px-4 py-2 rounded">
        <Text className="text-white font-semibold">Press Me</Text>
      </Pressable>
    </View>
  );
};

export default App;

5. Props

Props được sử dụng để giao tiếp giữa các thành phần trong React Native, cho phép dữ liệu dịch chuyển từ thành phần mẹ sang thành phần con. Cũng giống như style, có nhiều cách để quản lý props. Sự nhất quán là chìa khóa để thành công, vì vậy bạn nên tuân thủ nghiêm ngặt trong suốt dự án của mình.

Ngoài ra, hãy luôn hủy cấu trúc props để có code sạch hơn và dễ đọc hơn. Hủy cấu trúc không chỉ cải thiện khả năng đọc mà còn giúp dễ dàng phát hiện ra props nào mà một thành phần đang sử dụng.

const MyComponent = ({ title, subtitle }) => {
  return (
    <View>
      <Text>{title}</Text>
      <Text>{subtitle}</Text>
    </View>
  );
};

6. Quản lý State

Quản lý State hiệu quả sẽ đảm bảo ứng dụng vẫn hoạt động mượt mà và dễ quản lý khi bạn phát triển thêm các đoạn mã. Ngày nay, chúng ta có nhiều lựa chọn để chọn quản lý state một cách tốt nhất. a. Ưu tiên local state hơn global state b. Sử dụng Context API cho trạng thái đơn giản c. Sử dụng State Management Library cho các state phức tạp d. Cập nhật các State không thay đổi e. Ưu tiên redux toolkit hơn redux

7. Phân tích sự cố

Để đảm bảo ứng dụng của bạn hoạt động tốt và giảm sự cố, điều quan trọng là phải triển khai phân tích sự cố và theo dõi lỗi:

a. Sử dụng các công cụ phân tích sự cố Bạn có thể sử dụng các công cụ như Firebase, Crashlytics hoặc Sentry

b. Kiểm tra tính ổn định của ứng dụng Chạy thử nghiệm tự động và thử nghiệm ứng suất thủ công để phát hiện sự cố ngoài ý muốn. Sử dụng các dịch vụ như TestFlight hoặc Google Play Beta Testing để theo dõi dễ dàng hơn.

Bạn có thể theo dõi cả lỗi gốc (iOS/Android) và lỗi JavaScript. Sử dụng ErrorBoundary để bắt lỗi JavaScript và ghi chúng vào dịch vụ phân tích lỗi.

c. Theo dõi JS và Lỗi gốc

import React from 'react';
import * as Sentry from '@sentry/react-native';

class ErrorBoundary extends React.Component {
  componentDidCatch(error, errorInfo) {
    Sentry.captureException(error, { extra: errorInfo });
  }

  render() {
    if (this.state.hasError) {
      return <Text>Something went wrong.</Text>;
    }

    return this.props.children;
  }
}

8. Ghi nhật ký (Logging)

Việc ghi lại nhật ký giúp theo dõi hành vi của ứng dụng, gỡ lỗi và thu thập số liệu phân tích.

a. Sử dụng Logging framework

  • React Native Logger: Một trình ghi nhật ký dễ sử dụng được thiết kế riêng cho React Native.
  • Winston: Một thư viện ghi nhật ký đa phương tiện có thể hoạt động với cả React Native và Node.js.
import logger from 'react-native-logger';

logger.log('This is a debug log');
logger.warn('This is a warning log');
logger.error('This is an error log');

b. Phân biệt các mức Log Sử dụng các mức nhật ký thích hợp như debug, info, warn, và error.

Trong quá trình sản xuất, hãy giảm thiểu sự rườm rà của việc ghi nhật ký bằng cách chỉ cho phép ghi nhật ký lỗi và cảnh báo, trong khi ở chế độ phát triển, hãy sử dụng gỡ lỗi và thông tin.

c. Ghi nhật ký từ xa Hãy cân nhắc việc gửi nhật ký đến một dịch vụ ghi nhật ký từ xa như:

  • Papertrail
  • Loggly
  • Firebase Analytics

d. Ghi lại thông tin nhạy cảm một cách cẩn thận Tránh ghi lại thông tin nhạy cảm của người dùng như mật khẩu, mã thông báo hoặc dữ liệu cá nhân.

9. Testing

Testing cho mọi dự án là điều vô cùng quan trọng. Là một lập trình viên, chất lượng các đoạn mã là trách nhiệm hàng đầu không thể bỏ qua. Bạn có thể sử dụng các phương pháp Testing phổ biến như:

  • Kiểm thử đơn vị
  • Kiểm thử tích hợp
  • Kiểm thử từ đầu đến cuối

Hãy dành thời gian nhất định cho việc kiểm thử từ đầu đến cuối. Có nhiều công cụ có sẵn để giúp bạn có thể thực hiện. Cảm ơn các bạn đã theo dõi.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí