background
The pull-down refresh and pull-up loading function is a component that is used very frequently on the mobile terminal, whether it is an App or a small program. When developing RN recently, I thought that this wheel should be very mature, so I github
all over 060b378959bd4e and couldn't find it. A refreshing component that feels very perfect, and many of the components with high star numbers were maintained a few years ago. When it comes to this, I have to complain. The ecology of RN is really too narrow in China, and it is a little bit niche. One question, the probability that a domestic search engine can find the answer is 50%, the probability of a certain song is 80%, and the repetition rate is very high. I have always thought that RN will be because react
, the community should be very perfect, the result disappointed me .
After struggling for a while, I decided to use RN's own component- flatList
, which was slightly encapsulated. There was no problem in using the Tab routing page, but when using the details page, I encountered the first load and switch tab. , The indicator did not show the bug when flatList was refreshed. I searched the entire network and only encountered it by foreign friends. I also saw the issue of rn, but it was about 18 years old. It was closed and there was no solution. The only I met someone who was exactly like me. His solution was to save the country by curve. Every time he refreshed, he made the list roll back to the top (because the indicator was not displayed, in fact, the list was rolled to the bottom to cover the chrysanthemum), which was unacceptable. This solution.
Development environment
RN version: 0.64.0
UI component library: react native elements
Component type: functional (hooks)
Navigation version (react native navigation): 5.X
Try the solution
No matter how you set the height of the list, or the height of the outer layer, the hard-coded height and the flex setting to 1 have all been tried, all of which are useless.
expected outcome
actual results
solution
After numerous times of debugging, I found that after removing the Header component of the react native elements component library, the chrysanthemum that entered the page for the first time was displayed normally, but the switching page still did not display. Because I want the list component to be displayed in a safe area, my flatList wraps a layer of SafeAreaView, and the style is set to flex: 1. When I tried to remove it, I replaced it with View, and now the result is displayed as I expected.
Parent component:
<View style={common.container}>
<ButtonGroup
onPress={updateIndex}
selectedIndex={selectedIndex}
buttons={['文件', '流程中心']}
containerStyle={styles.buttonGroup}
textStyle={styles.buttonGroupText}
/>
{selectedIndex === 0 ? <ProjectFileList /> : <ProjectWorkflow />}
</View>
Subassembly:
<View style={styles.container}>
<SearchBar
containerStyle={styles.searchBarContainer}
inputStyle={styles.searchInput}
inputContainerStyle={styles.searchInputContainer}
lightTheme={true}
placeholder="搜索"
/>
<RefreshableList
loadMore={loadMore}
data={dataList}
renderItem={renderItem}
refreshing={refreshing}
onRefresh={handleRefresh}
onEndReached={handleLoadMore}
keyExtractor={item => item.resId}
/>
</View>
Custom Header
After enabling the Header of react native elements, I started to look for an alternative Header solution, and finally decided to use the API provided by react native navigation.
screenOptions configures the default parameters of page navigation
Configure the global unified style of navigation:
<Stack.Navigator
initialRouteName="Login"
screenOptions={({ navigation }) => {
return {
headerStyle: {
backgroundColor: colors.primary
},
headerTitleStyle: {
color: '#FFFF'
},
headerBackTitleStyle: {
color: '#FFFF'
},
headerBackTitleVisible: false,
headerBackImage: () => (
<TouchableOpacity onPress={navigation.goBack}>
<Ionicons name="arrow-back" size={24} color={'#fff'} />
</TouchableOpacity>
),
headerLeftContainerStyle: {
paddingLeft: 10
},
headerRightContainerStyle: {
paddingRight: 10
}
};
}}
>
{// 页面的若干配置...}
</Stack.Navigator>
NavigationContainer can accept a theme parameter, accept the theme style, and use useTheme
to get the global style in the route.
<NavigationContainer theme={MyTheme}>
{// 若干配置...}
</NavigationContainer>
MyTheme.js
import { DefaultTheme } from '@react-navigation/native';
const MyTheme = {
...DefaultTheme,
colors: {
...DefaultTheme.colors,
primary: '#0784ff',
bgGray: '#efeff3',
text: '#262626',
infoText: '#909399'
}
};
export default MyTheme;
So if some navigation needs some custom button events that need to be linked to the page, how to deal with it?
In fact, there is a setOptions method in navigation, which is the same function as when you configure Header Title, backTitle, etc. when configuring page routing.
// 设置自定义header
useLayoutEffect(() => {
navigation.setOptions({
headerRight: () => (
<TouchableOpacity onPress={() => drawerRef.current.toggleSideMenu()}>
<Ionicons name="menu" size={24} color={'#fff'} />
</TouchableOpacity>
),
headerTitle: () => (
<Text style={common.headerTitleText}>{route.params.name}</Text>
)
});
}, [navigation]);
flatList component
I encapsulated the general method, the method that needs to be implemented on the page is passed to the component through props, and I fixed the bug that may be encountered when the flatLIst component is pulled up and loaded.
import React, { useEffect, useState } from 'react';
import { View, FlatList, ActivityIndicator, Text } from 'react-native';
import styles from './styles';
import Empty from '../Empty';
const RefreshableList = props => {
const { setEndReachedCalled, loadMore } = props;
const renderFooter = () => {
return loadMore ? (
<View style={styles.footer}>
<ActivityIndicator />
<Text>正在加载更多数据...</Text>
</View>
) : (
<></>
);
};
return (
<FlatList
{...props}
contentContainerStyle={props.data.length ? null : { flexGrow: 1 }}
onEndReachedThreshold={0.2}
onMomentumScrollBegin={() => {
// 有些页面遇到第一次加载就触发loadMore的情况,如首页项目中心,遇到此情况需要传递setEndReachedCalled函数控制触发条件
setEndReachedCalled ? setEndReachedCalled(false) : null;
}}
ListEmptyComponent={() => <Empty />}
ItemSeparatorComponent={
// eslint-disable-next-line no-undef
Platform.OS !== 'android' &&
(({ highlighted }) => (
<View style={[styles.separator, highlighted && { marginLeft: 0 }]} />
))
}
ListFooterComponent={renderFooter}
/>
);
};
export default RefreshableList;
to sum up
RN stepped on the pit one step at a time, and the community couldn't give it, so we figured out how to solve it.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。