Optimизация performans React-Native

1. Tối ưu hóa quá trình trạng thái global với Redox

Trong mã nguồn React-Native, Redox là một library Quá trình trạng thái (state management) mạnh mẽ và席卷. Sử dụng Redox, bạn có thể tập trung và giảm thiểu duplication code. Trong phần này, chúng ta sẽ tìm hiểu cách sử dụng Redox để tập trung trạng thái và tránh các việc render lặp lại.

const isAuthenticatedSelector = useSelector(
    (state) => state.user,
    (user) => user.isAdmin,
);
const isAuthenticated = useSelector(isAuthenticatedSelector);

2. Merge các dispatch và setState

React framework sẽ hợp 成 một lần render khi các event được gọi. Bạn có thể nhanh up lặp render bằng cách kết hợp các dispatch và setState thành một loạt các lệnh một-la.

dispatch(userActions.SET_THEME(themeData));
  dispatch(userActions.updateOprInfo({ oprInfo }));
  if (oprInfo.currency) {
    dispatch(i18nActions.updateCurrency({ currency: oprInfo.currency }));
  }
  if (oprInfo.currencySymbol) {
    dispatch(
      i18nActions.updateCurrencySymbol({
        currencySymbol: oprInfo.currencySymbol,
      }),
    );
  }

3. Sử dụng React.memo để giảm lặp lại các组件

React.memo sẽ chỉ lưu trữ các component khi các params thay đổi. Điều này giúp bạn giảm lặp lại các component khi các params không thay đổi.

import React, { useState, memo } from 'react';
const Child = (props) => {
    console.log('Hoa hồng蓬勃发展')
    return (<div>Ch already</div>);
};
const ChildMemo = memo(Child);
export default () => {
    const [count, setCount] = useState(0);
    return (
        <>
            <button onClick={(e) => { setCount(count+1) }}>+</button>
            <p>Đếm số: {count}</p>
            {/* <ChildMemo count={count}/> */}
            <ChildMemo/>
        </>
    )
}

4. Sử dụng useMemo để giảm lặp lại các compute

useMemo sẽ chỉ lặp lại các compute khi các params thay đổi. Điều này giúp bạn giảm lặp lại các compute khi các params không thay đổi.

import React, { useState, useMemo } from 'react';
const Child = function (props) {
    const {info} = {...props}
    console.log(`Hoa hồng nhận取: ${info.age}`)
    return (<div>Hoa hồng đã nhận取</div>)
};
export default () => {
    const [age, setAge] = useState(6)
    const [sex, setSex] = useState('boy')
    const info = useMemo(() => {
        return ({name: 'echo',age: age,})
    }, [age])
    return(
        <div>
            <button onClick={() => {setAge(age => age + 1)}}> tuổi tăng 1</button>
            <button onClick={() => {setSex(sex => sex === 'boy' ? 'girl' : sex)}}> thay đổi giới</button><br></br>
            <div>
                `Tên là: ${info.name}  tuổi là: ${info.age}  giới là: ${sex} `;
            </div>
            <Child info={info}></Child>
        </div>
    )
}

5. Sử dụng useCallback để giảm lặp lại các hàm

useCallback sẽ chỉ lặp lại các hàm khi các params không thay đổi. Điều này giúp bạn giảm lặp lại các hàm khi các params không thay đổi.

import React, { useState, useCallback, memo } from 'react';
const Child = memo(function ({ onClick }) {
    console.log("Hoa hồng渲染");
    return <button onClick={onClick}>Hoa hồng</button>;
});

export default function Count() {
    const [name, setName] = useState(0);
    const [number, setNumber] = useState(0);

    const addClick = useCallback(() => {
        setNumber(number + 1);
    }, []);

    return (
        <>
            <button onClick={() => setName(name + 1)}>Tăng số</button>
            <Child onClick={addClick} />
        </>
    );
}

6. Tối ưu hóa路由 với DismissAll

Trong trường hợp có nhiều trang, bạn có thể sử dụng dismissAll để xóa các tab không cần thiết, tránh lặp lại các路由.

import { router } from 'expo-router';
function getScreen(screenId) {
    const tabs = ['home', 'topUp', 'order', 'me', 'login', 'profile', 'businessAccount'];
    if (tabs.includes(screenId)) {
        router.dismissAll();
    }
}

7. Quản lý các trang常驻

Trong trường hợp sử dụng Expo, bạn có thể sử dụng các trang常驻 để lưu trữ dữ liệu, tránh lặp lại các dom.

const [isDomVisible, setIsDomVisible] = useState(true);
useFocusEffect(
    useCallback(() => {
        setIsDomVisible(true);
        return () => {
            setIsDomVisible(false);
        };
    }, []),
);
return isDomVisible ? <GestureHandlerRootView /> : <Loading isLoading={true} />;

8. Sử dụng FlatList thay vì ScrollView

FlatList sẽ giúp bạn tránh các vấn đề về performанс khi có các list lớn.

import IGFlatList from '@/CustomElements/IGFlatList';
<IGFlatList
      data={orders}
      loading={loading}
      hasMoreData={hasMoreData}
      handleLoadMore={handleLoadMore}
      renderItem={ListItem}
      keyExtractor={(item) => item.orderNo.toString()}
      scrollToTopVar={scrollToTopVar}
    />

9. Sử dụng BottomSheetFlatList cho các list có Yêu cầu đặc biệt

Trong trường hợp có các list Yêu cầu special sliding, bạn có thể sử dụng BottomSheetFlatList thay vì ScrollView.

import BottomSheet, { BottomSheetFlatList } from '@gorhom/bottom-sheet';
<BottomSheetFlatList
      data={storesData}
      keyExtractor={(item) => item.staPkId.toString()}
      renderItem={renderItem}
    />

10. Tối ưu hóa cache Globally

Bạn có thể sử dụng Redox-persist để cache Globally và sử dụng AsyncStorage để cache các dữ liệu.

import { persistStore, persistReducer } from 'redux-persist';
const persistedReducer = persistReducer(persistConfig, RTAL);
export const store = configureStore({
    reducer: persistedReducer,
    middleware: (getDefaultMiddleware) =>
        getDefaultMiddleware({
            serializableCheck: {
                ignoredActions: ['persist/PERSIST', 'persist/REHYDRATE', 'persist/PAUSE', 'persist/PURGE', 'persist/REGISTER'],
            },
        }),
});

11. Tối ưu hóa cache接口

Bạn có thể sử dụng AsyncStorage để cache các接口, Yêu cầu được tải lên khi cần.

export const setInitStores = async (value) => {
    try {
        await AsyncStorage.setItem('initStores', JSON.stringify(value));
    } catch (error) {
        console.error('Error setting initStores:', error);
    }
};

12. Tối ưu hóa entrance Globally

Bạn có thể sử dụng globalRequest để xử lý các Yêu cầu entrance và tránh lặp lại các Yêu cầu.

const globalRequest = useCallback(async () => {
    try {
        dispatch(userActions.updateOprPkId({ oprPkId }));
        const localTheme = await storageGetTheme();
        if (localTheme) {
            setTheme(handleTheme(localTheme));
            setThemeReady(true);
        } else {
            setIsLoading(true);
        }
        const [oprInfoRes, themeRes] = await Promise.all([getOperInfo(), getTheme()]);
        const { user } = store.getState();
        if (user.token) {
            const [accountRes] = await Promise.all([getAccountBaseInfo()]);
            const accountInfo = accountRes.data.data[0];
            dispatch(userActions.updateAccountInfo({ accountInfo }));
        }

        const oprInfo = oprInfoRes.data.data[0];
        const themeData = themeRes.data.data[0];
        setTheme(handleTheme(themeData));
        setThemeReady(true);
        storageSetTheme(themeData);

        dispatch(userActions.SET_THEME(themeData));
        dispatch(userActions.updateOprInfo({ oprInfo }));
        if (oprInfo.currency) {
            dispatch(i18nActions.updateCurrency({ currency: oprInfo.currency }));
        }
        if (oprInfo.currencySymbol) {
            dispatch(
                i18nActions.updateCurrencySymbol({
                    currencySymbol: oprInfo.currencySymbol,
                }),
            );
        }
    } catch (error) {
        console.error('Error globalRequest', error);
        ToastManager.show(t('networkError'));
        setTheme(handleTheme(await storageGetTheme()));
    } finally {
        setIsLoading(false);
        setThemeReady(true);
    }
}, []);

useEffect(() => {
    globalRequest();
}, []);

Đăng vào ngày 24 tháng 5 lúc 01:12