Một dòng trạng thái đặt spinner cạnh chữ. Khi tải xong, bạn tắt animating nhưng khoảng trống cạnh chữ vẫn còn vì View bọc spinner vẫn nằm trong cây giao diện. Quyết định dừng indicator và quyết định bỏ vùng bố trí cần được viết rõ trong JSX.
Bài đối chiếu React Native 0.88 và tài liệu React hiện hành ngày 06/11/2026. JSX được rà thủ công; chưa build native, chạy Hermes hoặc đo layout trên Android/iOS. Demo dùng nút bật tắt trạng thái, không gọi API và không giả vờ một tác vụ mạng đã hoàn tất.
Xác định phần nào cần giữ ổn định
Nếu chữ phải giữ cùng vị trí khi loading đổi, bạn có thể luôn render một ô có kích thước cố định dành cho spinner. Nếu thiết kế muốn bỏ cả khoảng trống, điều kiện render phải bao gồm ô bọc ấy.
Đừng dựa vào việc vòng quay có nhìn thấy được hay không để suy luận bố trí của tổ tiên. View cha vẫn có thể giữ width, height, padding hoặc margin riêng. Trước khi chỉnh ActivityIndicator, tìm đúng component đang tạo khoảng trống.
1. So sánh hai hàng trong một màn hình
Dùng component sau trong project React Native đang chạy. Cùng một state điều khiển cả hai hàng để bạn có thể đối chiếu thay đổi:
import React, {useState} from 'react';
import {ActivityIndicator, Button, StyleSheet, Text, View} from 'react-native';
export default function SpinnerSlotDemo() {
const [loading, setLoading] = useState(true);
const label = loading ? 'Đang tải minh họa' : 'Đã dừng minh họa';
return (
<View style={styles.screen}>
<Button
title={loading ? 'Dừng spinner' : 'Bật spinner'}
onPress={() => setLoading(value => !value)}
/>
<Text>Hàng A: luôn giữ ô cho spinner</Text>
<View style={styles.row}>
<View style={styles.slot}>
<ActivityIndicator animating={loading} size="small" color="#2563eb" />
</View>
<Text style={styles.label}>{label}</Text>
</View>
<Text>Hàng B: bỏ cả ô khi dừng</Text>
<View style={styles.row}>
{loading ? (
<View style={styles.slot}>
<ActivityIndicator size="small" color="#2563eb" />
</View>
) : null}
<Text style={styles.label}>{label}</Text>
</View>
</View>
);
}
const styles = StyleSheet.create({
screen: {flex: 1, padding: 24, paddingTop: 48},
row: {flexDirection: 'row', alignItems: 'center', marginBottom: 24},
slot: {width: 24, height: 24, marginRight: 8,
alignItems: 'center', justifyContent: 'center'},
label: {flexShrink: 1},
});
Ở hàng A, View slot luôn có mặt dù loading bằng false. Ở hàng B, nhánh điều kiện bao cả View slot, nên trạng thái false không dựng ô này. Hai cách mô tả hai yêu cầu bố trí khác nhau, không cần đoán kích thước mặc định của spinner khi đã dừng.
24 trong style là đơn vị kích thước không gắn trực tiếp với pixel vật lý của màn hình. Ví dụ không quy định đường kính native của vòng quay phải đúng 24; đó là kích thước ô mà ứng dụng dành chỗ.
2. Kiểm tra props có khác biệt nền tảng
Tài liệu ActivityIndicator liệt kê hidesWhenStopped cho iOS, mặc định true. Không dùng prop ấy làm hợp đồng chung để xóa wrapper trên cả Android và iOS. Khi cần vùng trống biến mất chắc chắn theo cấu trúc JSX, kiểm soát chính wrapper.
size small và large là các lựa chọn chung; kích thước số được tài liệu đánh dấu cho Android. Demo dùng small để tránh đặt một kích thước số rồi mặc định iOS sẽ nhận cùng hợp đồng. Nếu sản phẩm đòi hình thức khớp chặt, thử trên từng nền tảng thay vì suy luận từ một simulator.
Kiểm tra theo chuyển trạng thái
Khi loading true, xác nhận cả hai hàng có spinner và chữ dễ đọc. Bấm dừng, kiểm tra hàng A còn ô giữ chỗ còn hàng B bỏ ô. Bật lại nhiều lần để quan sát vị trí chữ, đặc biệt với font lớn và màn hình hẹp.
Có thể dùng inspector hoặc onLayout trong một bản test để ghi bounds của slot và Text. Những số đo ấy cần đến từ bản build thực tế; bài này không đưa tọa độ hoặc thời gian chuyển trạng thái như kết quả đã đo. Kiểm tra cả khoảng margin của component cha khi có khoảng trống ngoài dự kiến.
Giới hạn của spinner trong luồng tải thật
ActivityIndicator chỉ biểu diễn một trạng thái; nó không quản lý request, timeout hoặc retry. Khi ghép vào luồng tải thật, loading phải phản ánh đúng tác vụ đang được ứng dụng theo dõi, kèm nhánh lỗi và dữ liệu rỗng phù hợp.
Không dùng một vòng quay liên tục làm thông tin duy nhất cho người dùng. Demo có Text trạng thái; sản phẩm vẫn cần kiểm tra trải nghiệm accessibility riêng trên nền tảng đích. Bài chưa thử VoiceOver, TalkBack hoặc đưa ra cam kết rằng việc dừng animation sẽ tự thông báo cho screen reader.
Chọn giữ chỗ nếu cần vị trí chữ ổn định; chọn bỏ wrapper khi cần thu gọn hàng. Viết lựa chọn ấy thành điều kiện render rõ ràng sẽ giúp người đọc code hiểu khoảng trống nào là có chủ đích.

