本文在 Expo 环境中编写,但内容适用于所有 React Native 环境。 同时,假设项目已经完成基本配置。
ActivityIndicator 与 react-native-skeleton-placeholder。ActivityIndicator 是内置的圆形加载指示器,react-native-skeleton-placeholder 则会预先展示空白的骨架结构。根据场景选择合适的指示器,可以为用户提供更好的体验。App.js 文件,编写以下代码。这段代码会在用户每次刷新页面时,等待 2 秒后显示当前时间。刷新原理请参考 React Native RefreshControl 文章。import React, { useEffect, useState } from 'react';
import { Text, ScrollView, RefreshControl, View, SafeAreaView } from 'react-native';
const Card = () => {
const [now, setNow] = useState('');
useEffect(() => {
setTimeout(() => {
setNow(new Date().toLocaleString());
}, 2000);
}, []);
return (
<View style={{ flex: 1 }}>
{Array.from({ length: 100 }).map((_, index) => (
<Text key={index} style={{ textAlign: 'center', justifyContent: 'center', fontSize: 20 }}>{`${now}`}</Text>
))}
</View>
);
};
const List = () => {
const [key, setKey] = useState(new Date().getTime());
const [refreshing, setRefreshing] = useState(false);
const handleRefresh = () => {
setRefreshing(true);
setKey(new Date().getTime());
setRefreshing(false);
};
return (
<SafeAreaView style={{ flex: 1, backgroundColor: 'white', padding: 20 }}>
<ScrollView
refreshControl={
<RefreshControl refreshing={refreshing} onRefresh={handleRefresh} colors={['blue', 'red', 'green']} />
}
>
<View style={{ flex: 1, flexDirection: 'row' }}>
<Card key={key} />
</View>
</ScrollView>
</SafeAreaView>
);
};
export default List;
ActivityIndicator 是内置组件,无需额外安装。要使用 ActivityIndicator,按如下方式编写代码即可。
为了与刷新指示器区分,这里将其设为蓝色。另外,添加 isLoading 状态,让指示器只在数据加载期间显示。import React, { useEffect, useState } from 'react';
import { Text, ScrollView, RefreshControl, View, SafeAreaView, ActivityIndicator } from 'react-native';
const Card = () => {
const [now, setNow] = useState('');
const [isLoading, setIsLoading] = useState(true); // isLoading 추가
useEffect(() => {
setIsLoading(true); // 데이터 로딩 시작
setTimeout(() => {
setNow(new Date().toLocaleString());
setIsLoading(false); // 데이터 로딩 완료
}, 2000);
}, []);
return (
<View style={{ flex: 1 }}>
{isLoading ? (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center', height: 200 }}>
<ActivityIndicator size="large" color="blue" /> // ActivityIndicator 추가
</View>
) : (
Array.from({ length: 100 }).map((_, index) => (
<Text key={index} style={{ textAlign: 'center', justifyContent: 'center', fontSize: 20 }}>{`${now}`}</Text>
))
)}
</View>
);
};
const List = () => {
const [key, setKey] = useState(new Date().getTime());
const [refreshing, setRefreshing] = useState(false);
const handleRefresh = () => {
setRefreshing(true);
setKey(new Date().getTime());
setRefreshing(false);
};
return (
<SafeAreaView style={{ flex: 1, backgroundColor: 'white', padding: 20 }}>
<ScrollView
refreshControl={
<RefreshControl refreshing={refreshing} onRefresh={handleRefresh} colors={['blue', 'red', 'green']} />
}
>
<View style={{ flex: 1, flexDirection: 'row' }}>
<Card key={key} />
</View>
</ScrollView>
</SafeAreaView>
);
};
export default List;
react-native-skeleton-placeholder 是一种提前显示空白骨架结构的指示器。使用 react-native-skeleton-placeholder 前,需要先安装它。运行下面两条命令中的任意一条即可。npm install @react-native-masked-view/masked-view react-native-linear-gradient --save
npm install react-native-skeleton-placeholder --saveyarn add @react-native-masked-view/masked-view react-native-linear-gradient
yarn add react-native-skeleton-placeholderreact-native-skeleton-placeholder 时,按如下方式编写代码。
import React, { useEffect, useState } from 'react';
import { Text, ScrollView, RefreshControl, View, SafeAreaView } from 'react-native';
import SkeletonPlaceholder from 'react-native-skeleton-placeholder';
const Card = () => {
const [now, setNow] = useState('');
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
setIsLoading(true);
setTimeout(() => {
setNow(new Date().toLocaleString());
setIsLoading(false);
}, 2000);
}, []);
return (
<View style={{ flex: 1 }}>
{isLoading ? (
<SkeletonPlaceholder borderRadius={4}>
<Text style={{ marginTop: 6, fontSize: 14, lineHeight: 18 }}>Hello world</Text>
</SkeletonPlaceholder>
) : (
Array.from({ length: 100 }).map((_, index) => (
<Text key={index} style={{ textAlign: 'center', justifyContent: 'center', fontSize: 20 }}>{`${now}`}</Text>
))
)}
</View>
);
};
const List = () => {
const [key, setKey] = useState(new Date().getTime());
const [refreshing, setRefreshing] = useState(false);
const handleRefresh = () => {
setRefreshing(true);
setKey(new Date().getTime());
setRefreshing(false);
};
return (
<SafeAreaView style={{ flex: 1, backgroundColor: 'white', padding: 20 }}>
<ScrollView
refreshControl={
<RefreshControl refreshing={refreshing} onRefresh={handleRefresh} colors={['blue', 'red', 'green']} />
}
>
<View style={{ flex: 1, flexDirection: 'row' }}>
<Card key={key} />
</View>
</ScrollView>
</SafeAreaView>
);
};
export default List;ERROR Warning: TypeError: Cannot read property 'bubblingEventTypes' of null 错误,我正在寻找解决方法。找到后会更新本文。
GitHub issue↗