Q5. Các vấn đề thường gặp về performance trong React Native?

Re-render không cần thiết

Vấn đề:

Re-render không cần thiết có thể làm giảm performance của ứng dụng trong quá trình re-rendering tốn nhiều tài nguyên, đặc biệt khi cây component trở nên phức tạp

Giải pháp:

  • PureComponent và memo: Sử dụng React.PureComponent hoặc React.memo để tránh re-render không cần thiết

  • useCallback và useMemo: Sử dụng useCallback và useMemo để tối ưu hoá các hàm callback và giá trị được tính toán

import React, { memo, useCallback, useState } from 'react';
import { Text, Button, View } from 'react-native';

const ExpensiveComponent = memo(({ onPress }) => {
  return <Button title="Press me" onPress={onPress} />;
});

const MyComponent = () => {
  const [count, setCount] = useState(0);

  const handlePress = useCallback(() => {
    setCount(count + 1);
  }, [count]);

  return (
    <View>
      <Text>Count: {count}</Text>
      <ExpensiveComponent onPress={handlePress} />
    </View>
  );
};

Memory leaks

Vấn đề:

Memory leaks xảy ra khi các đối tượng không được giải phóng bộ nhớ sau khi không còn cần thiết, dẫn đến tăng dần lượng bộ nhớ sử dụng

Giải pháp:

  • Cleanup trong useEffect: Đảm bảo cleanup đúng cách trong useEffect bằng cách trả về một hàm cleanup

  • Unmount Listeners: Huỷ bỏ các listeners và subscriptions khi component unmount

import React, { useEffect } from 'react';
import { View } from 'react-native';

const MyComponent = () => {
  useEffect(() => {
    const intervalId = setInterval(() => {
      // some logic
    }, 1000);

    return () => clearInterval(intervalId); // cleanup
  }, []);

  return <View />;
};

Quản lý danh sách lớn

Vấn đề:

Hiển thị và quản lý danh sách lớn có thể dẫn đến hiệu suất kém, đặc biệt khi tất cả các item được render cùng lúc

Giải pháp:

  • FlatList và SectionList: Sử dụng FlatList và SectionList thay vì ScrollView để tối ưu hoá render danh sách lớn

  • Virtualized List: Đảm bảo rằng chỉ những phần tử đàng nhìn thấy mới được render

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

const MyComponent = () => {
  const data = Array.from({ length: 1000 }, (_, i) => `Item ${i}`);

  return (
    <FlatList
      data={data}
      renderItem={({ item }) => <Text>{item}</Text>}
      keyExtractor={(item, index) => index.toString()}
    />
  );
};

Hình ảnh lớn

Vấn đề:

Sử dụng hình ảnh lớn không được tối ưu hoá có thể làm giảm hiệu suất ứng dụng

Giải pháp:

  • Resize và nén hình ảnh: Tối ưu hoá kích thước và nén hình ảnh trước khi sử dụng

  • react-native-fast-image: Sử dụng thư viện như react-native-fast-image để cải thiện hiệu suất tải và hiển thị hình ảnh

      import FastImage from 'react-native-fast-image';
    
      const MyComponent = () => {
        return (
          <FastImage
            style={{ width: 200, height: 200 }}
            source={{
              uri: 'https://example.com/image.png',
              priority: FastImage.priority.high,
            }}
            resizeMode={FastImage.resizeMode.contain}
          />
        );
      };
    

Xử lý animation

Vấn đề:

Animations có thể gây giảm hiệu suất nếu không được tối ưu hoá đúng cách

Giải pháp:

  • useNativeDriver: Sử dụng useNativeDriver cho các animations để tận dụng tối đa hiệu suất của native thread

  • Reanimated và Lottie: Sử dụng thư viện như react-native-reanimated hoặc lottie-react-native cho các animation phức tạp và hiệu quả

      import React, { useRef, useEffect } from 'react';
      import { Animated } from 'react-native';
    
      const MyComponent = () => {
        const fadeAnim = useRef(new Animated.Value(0)).current;
    
        useEffect(() => {
          Animated.timing(fadeAnim, {
            toValue: 1,
            duration: 1000,
            useNativeDriver: true,
          }).start();
        }, [fadeAnim]);
    
        return <Animated.View style={{ opacity: fadeAnim }} />;
      };
    

    6. Khởi động ứng dụng chậm

    Vấn đề:

    Ứng dụng có thời gian khởi động chậm có thể gây trải nghiệm người dùng không tốt.

    Giải pháp:

    • Code splitting và lazy loading: Sử dụng kỹ thuật phân tách mã và lazy loading để tải các phần của ứng dụng khi cần thiết.

    • Optimize bundle size: Tối ưu hóa kích thước bundle bằng cách loại bỏ các mã không cần thiết và sử dụng các thư viện nhẹ hơn.

7. Background Tasks

Vấn đề:

Xử lý các tác vụ nền có thể gây chậm hiệu suất nếu không được quản lý đúng cách.

Giải pháp:

  • react-native-background-fetch: Sử dụng thư viện như react-native-background-fetch để quản lý các tác vụ nền.

  • Headless JS: Sử dụng Headless JS để thực hiện các tác vụ nền khi ứng dụng không hoạt động.

    jsxCopy codeimport BackgroundFetch from "react-native-background-fetch";

    BackgroundFetch.configure({
      minimumFetchInterval: 15,
      stopOnTerminate: false,
      startOnBoot: true,
    }, async (taskId) => {
      // Perform background task
      console.log("[BackgroundFetch] taskId: ", taskId);
      BackgroundFetch.finish(taskId);
    }, (taskId) => {
      console.log("[BackgroundFetch] TIMEOUT taskId: ", taskId);
      BackgroundFetch.finish(taskId);
    });