RenderFooter called infinitely - react-native

When I reach the bottom of FlipKarts recyclerlistview it enters an infinite loop calling renderFooter thousands of times and I cant scroll up anymore.... No idea what this could be. It should scroll to the bottom and then simply bounce up or just stay at the bottom. Instead it gets stuck and Ive found nothing on github or stackoverflow.
renderFooter() {
if(this.state.outPosts == false) {
return <View style={{
alignContent:'center',
justifyContent:'center',
alignItems:'center',
}}>
<ActivityIndicator
style={{
marginTop:15*factor_ver,
marginBottom:15*factor_ver,
}}
size={"small"}
color={'#9b9b9b'}
/>
</View>
}
else if(this.state.outPosts == true) {
return <View style={{
height:140*factor_hor,
marginTop:20,
alignContent:'center',
justifyContent:'center',
alignItems:'center',
}}>
<Text style={{textAlign:'center', fontSize:22*factor_hor, fontFamily:'Avenir Next', color:'#9b9b9b',}}>
No posts! :(
</Text>
<View style={{flex:1,}}></View>
<Block width={60*factor_hor}
height={60*factor_hor}
style={{
justifyContent:'center',
alignContent:'center',
flex: 1,
}}
/>
<View style={{height:30}}></View>
</View>
}
}
<RecyclerListView
style={{flex:1, backgroundColor:'#f7f7f7', paddingTop:8*factor_hor,}}
extendedState={this.state}
rowRenderer={this._renderRow}
dataProvider={this.state.dataProvider}
layoutProvider={this._layoutProvider}
showsVerticalScrollIndicator={false}
onEndReached={() => this.fetchPosts()}
onEndReachedThreshold={500}
renderFooter={this.renderFooter}
onScroll={(e) => this.handleScroll(e)}
scrollThrottle={250}
refreshControl={
<RefreshControl
tintColor={'white'}
refreshing={false}
onRefresh={() => {
this.setState({isLoad:true}), this.refresh_feed()}}
/>}
/>

great so Im going to leave this up here because theres nothing else I could find to explain this. If youre using React native FlipKart recyclerlistview and you render empty views then when you scroll to the bottom this glitch happens where you cant scroll up and renderFooter is called infinitely. Check to make sure each rendered view has at least a container to fill it.

Related

react-native-gesture-handler Swipable does not take the entire screen

I have the following code:
<View style={{ backgroundColor: 'black'}}>
<ArticleSwipable
ref={swipeableRef}
renderRightActions={this.renderRightActions}
onSwipeableClose={() => console.log('close')}
onSwipeableOpen={loadArticleSwipe}
onSwipeableWillOpen={() =>{ setzIndex(100); }}>
<ArticleScreen
article={article}
navigation={navigation}
scrollRef={scrollRef}
header={<Header
onFavouritePress={toggleFavouriteButton}
favouriteButtonIcon={favouriteButtonIcon} />}
isLoading={isLoading}/>
</ArticleSwipable>
<LoadingComponent opacity={loadingFadeAnim} zIndex={zIndex} isLoading={isLoading} />
</View>
where ArticleSwipable is a react-native-gesture-handler/Swipable component but with overridden close method.
ArticleScreen has the following structure:
<View>
<ScrollView>...</ScrollView>
</View>
My goal is to make the Swipeable Component take the entire screen but now if the content is less than the height of the screen will display the white rectangle at the bottom.
Example
If the content is bigger than the height of the screen then everyting is ok.
How can I get rid of the white rectangle at the bottom?
Try this once :
<View style={{ backgroundColor: 'black' ,flex:1}}>
<ArticleSwipable
ref={swipeableRef}
renderRightActions={this.renderRightActions}
onSwipeableClose={() => console.log('close')}
onSwipeableOpen={loadArticleSwipe}
onSwipeableWillOpen={() =>{ setzIndex(100); }}>
<ArticleScreen
article={article}
navigation={navigation}
scrollRef={scrollRef}
header={<Header
onFavouritePress={toggleFavouriteButton}
favouriteButtonIcon={favouriteButtonIcon} />}
isLoading={isLoading}/>
</ArticleSwipable>
<LoadingComponent opacity={loadingFadeAnim} zIndex={zIndex} isLoading={isLoading} />
</View>
And also this :
<View style={{flex:1}} >
<ScrollView>...</ScrollView>
</View>

ReactNative - FliatList turns white screen when render many item

Android : 4.4.2 , 8.0
React-native : 0.61.4
It only happens on android.
https://gfycat.com/flimsyastonishingguineafowl
<FlatList
style={{ transform: [{ scaleY: -1 }], marginBottom: 10 }}
removeClippedSubviews
initialNumToRender={20}
data={replyList}
onEndReached={this.nextPage}
contentContainerStyle={{ justifyContent: 'flex-end', flexGrow: 1 }}
keyboardShouldPersistTaps="handled"
pinchGestureEnabled={false}
keyboardDismissMode="none"
keyExtractor={item => `${item.replyUID}reply`}
showsVerticalScrollIndicator={false}
renderItem={({ item }) => (
<RenderReplyItem
item={item}
/>
)}
onScroll={handleScroll}
ref={setRef}
scrollEventThrottle={16}
/>
export default class RenderReplyItem extends PureComponent {
render() {
const {
item,
} = this.props;
return (
<View style={[styles.replyContainer, { alignSelf: 'center', transform: [{ scaleY: -1 }] }]}>
<View style={styles.replyBackground}
>
<Text style={styles.replyContentStyle}
>
{item.content}
</Text>
<View style={styles.replyBottom}>
<Text style={styles.replyregisterDate}>
{item.replyUID}
</Text>
</View>
</View>
</View>
);
}
}
The screen turns white after 80 items have been rendered.
Then scroll down again and the screen will come back and the scroll will move randomly.
Other FlatLists experienced a similar phenomenon and disappeared after setting keyExtractor.
However, only after this page, the same thing happens after you set the keyExtractor.
duplicate of
alternative of flatlist in react-native with much improved performance
For improving flatlist performance tips see here

React Native warning: each child in a list should have a unique 'key' prop

I am creating a render function to display information from within an array. Everything is functioning completely fine, however when I run the project I get an warning saying that each child in the list requires a unique key. I researched all the reasons why this may be happening however I don't see why I am getting this warning. Please help me.
Here is the entire code, from setting the data and rendering the function, thank you:
this.state = {
feed: [{
username: ["Its_Jess: ", "Animal_Luver: ", "Kyl3_Rayn3r: ", "Smith_Family: "],
caption: ["The New Photoshoot was so much fun!", "AWWWW Look at them sleep!!", "Beautiful swim", "This photo is from our vacation <3"],
coments: ["View All 49 Comments", "View All 19 Comments", "View All 69 Comments", "View All 4 Comments"],
photo:[Pic1,Pic2,Pic4,Pic6],
avatar:[Pic1,Ava1,Ava2,Ava3]
}]
}
renderFeed = () => {
return this.state.feed.map((card, index) => {
return card.username.map((username, i) => {
if(card.caption[i])
return (
<View>
<TouchableHighlight
onPress={()=>this.toggleModal({photo:card.photo[i], avatar:card.avatar[i] ,caption:card.caption[i],username:card.username[i],coments:card.coments[i]})}
underlayColor="white">
<Card
key={`${i}_${index}`}
image={card.photo[i]}
containerStyle={{borderRadius:10, marginRight:1, marginLeft:1,}}>
<View
style={{ flex: 1, flexDirection: 'row', justifyContent: 'space-between' }}
>
<View style={{ flexDirection: 'row'}}>
<Avatar
key={card.avatar}
size="small"
rounded
source={card.avatar[i]}
/>
</View>
<View style={{flexDirection:'row'}}>
{this.state.isLiked[i] ?(
<Avatar
rounded
icon={{
name: 'heart-multiple-outline',
type: 'material-community',
}}
overlayContainerStyle={{
backgroundColor: '#ff4284',
marginLeft: 5,
}}
reverse
size="small"
onPress={()=> this.toggleLike(i)}/>
) : (
<Avatar
rounded
icon={{ name:'heart-multiple-outline', type:'material-community', color: '#ff4284'}}
overlayContainerStyle={{marginLeft:5}}
reverse
size='small'
onPress={()=> this.toggleLike(i)}/>
)}
<Avatar
reverse
rounded
icon={{ name:'comment-processing-outline', type:'material-community' }}
overlayContainerStyle={{backgroundColor: '#dbdbdb',marginLeft:5}}
size='small'/>
</View>
</View>
{ this.state.fontLoaded == true ? (
<View style={{flexDirection:'row'}}>
<Text style={{fontFamily: 'MontserratB', color:'#bf00b9', marginTop:10}} key={username}>{username}</Text>
<Text style={{fontFamily:'Montserrat', marginTop:10}} key={card.caption}>{card.caption[i]}</Text>
</View>
) : (<Text> Loading...</Text>)
}
<Text style={{marginTop:4, color:'#878787'}} key={card.coments}>{card.coments[i]}</Text>
</Card>
</TouchableHighlight>
</View>
);
return <React.Fragment />;
});
})
}
render(){
return (
<View>
{this.renderFeed()}
</View>
)}
The issue was in where I was declaring my key. I moved key={`${i}_${index}`} from the <Card> element up to the <View> element and now the warning is gone
It's always a good practice to assign each of the elements in the array with a unique key because Keys are necessary to improve performance of your React app. Please refer the below article to get the exact knowledge of why it's necessary.
Keys

How to set the textinput box above the Keyboard while entering the input field in react native

I am using react-native TextInput component. Here I need to show the InputBox above the keyboard if the user clicks on the textInput field.
I have tried below but i am facing the issues
1. Keyboard avoiding view
a. Here it shows some empty space below the input box
b. Manually I need to scroll up the screen to see the input field which I was given in the text field
c. Input box section is hiding while placing the mouse inside the input box
2. react-native-Keyboard-aware-scroll-view
a.It shows some empty space below the input box
b.ScrollView is reset to the top of the page after I moving to the next input box
Here I set the Keyboard-aware-scroll-view inside the ScrollView component
Kindly clarify
My example code is
<SafeAreaView>
<KeyboardAvoidingView>
<ScrollView>
<Text>Name</Text>
<AutoTags
//required
suggestions={this.state.suggestedName}
handleAddition={this.handleAddition}
handleDelete={this.handleDelete}
multiline={true}
placeholder="TYPE IN"
blurOnSubmit={true}
style= {styles.style}
/>
</ScrollView>
</KeyboardAvoidingView>
</SafeAreaView>
[https://github.com/APSL/react-native-keyboard-aware-scroll-view]
Give your TextInput a position: absolute styling and change its position using the height returned by the keyboardDidShow and keyboardDidHide events.
Here is a modification of the Keyboard example from the React Native documentation for demonstration:
import React, { Component } from 'react';
import { Keyboard, TextInput } from 'react-native';
class Example extends Component {
state = {
keyboardOffset: 0,
};
componentDidMount() {
this.keyboardDidShowListener = Keyboard.addListener(
'keyboardDidShow',
this._keyboardDidShow,
);
this.keyboardDidHideListener = Keyboard.addListener(
'keyboardDidHide',
this._keyboardDidHide,
);
}
componentWillUnmount() {
this.keyboardDidShowListener.remove();
this.keyboardDidHideListener.remove();
}
_keyboardDidShow(event) {
this.setState({
keyboardOffset: event.endCoordinates.height,
})
}
_keyboardDidHide() {
this.setState({
keyboardOffset: 0,
})
}
render() {
return <View style={{flex: 1}}>
<TextInput
style={{
position: 'absolute',
width: '100%',
bottom: this.state.keyboardOffset,
}}
onSubmitEditing={Keyboard.dismiss}
/>
</View>;
}
}
First of all, You don't need any extra code for Android platform. Only keep your inputs inside a ScrollView. Just use KeyboardAvoidingView to encapsulate the ScrollView for iOS platform.
Create function such as below which holds all the inputs
renderInputs = () => {
return (<ScrollView
showsVerticalScrollIndicator={false}
style={{
flex: 1,
}}
contentContainerStyle={{
flexGrow: 1,
}}>
<Text>Enter Email</Text>
<TextInput
style={styles.text}
underlineColorAndroid="transparent"
/>
</ScrollView>)
}
Then render them inside the main view as below
{Platform.OS === 'android' ? (
this.renderInputs()
) : (
<KeyboardAvoidingView behavior="padding">
{this.renderInputs()}
</KeyboardAvoidingView>
)}
I have used this method and I can assure that it works.
If it is not working then there is a chance that you are missing something.
Hooks version:
const [keyboardOffset, setKeyboardOffset] = useState(0);
const onKeyboardShow = event => setKeyboardOffset(event.endCoordinates.height);
const onKeyboardHide = () => setKeyboardOffset(0);
const keyboardDidShowListener = useRef();
const keyboardDidHideListener = useRef();
useEffect(() => {
keyboardDidShowListener.current = Keyboard.addListener('keyboardWillShow', onKeyboardShow);
keyboardDidHideListener.current = Keyboard.addListener('keyboardWillHide', onKeyboardHide);
return () => {
keyboardDidShowListener.current.remove();
keyboardDidHideListener.current.remove();
};
}, []);
You can use a scrollview and put all components inside the scrollview and add automaticallyAdjustKeyboardInsets property to scrollview.it will solve your problem.
automaticallyAdjustKeyboardInsets Controls whether the ScrollView should automatically adjust its contentInset and
scrollViewInsets when the Keyboard changes its size. The default value is false.
<ScrollView automaticallyAdjustKeyboardInsets={true}>
{allChildComponentsHere}
<View style={{ height: 30 }} />//added some extra space to last element
</ScrollView>
Hope it helps.
you can use KeyboardAvoidingView as follows
if (Platform.OS === 'ios') {
return <KeyboardAvoidingView behavior="padding">
{this.renderChatInputSection()}
</KeyboardAvoidingView>
} else {
return this.renderChatInputSection()
}
Where this.renderChatInputSection() will return the view like textinput for typing message. Hope this will help you.
For android you can set android:windowSoftInputMode="adjustResize" for Activity in AndroidManifest file, thus when the keyboard shows, your screen will resize and if you put the TextInput at the bottom of your screen, it will be keep above keyboard
react-native-keyboard-aware-scroll-view caused similar issue in ios. That's when I came across react-native-keyboard-aware-view. Snippets are pretty much same.
<KeyboardAwareView animated={true}>
<View style={{flex: 1}}>
<ScrollView style={{flex: 1}}>
<Text style={{fontSize: 20, color: '#FFFFFF'}}>A</Text>
<Text style={{fontSize: 20, color: '#FFFFFF'}}>B</Text>
<Text style={{fontSize: 20, color: '#FFFFFF'}}>C</Text>
<Text style={{fontSize: 20, color: '#FFFFFF'}}>D</Text>
</ScrollView>
</View>
<TouchableOpacity style={{height: 50, backgroundColor: 'transparent', alignItems: 'center', justifyContent: 'center', alignSelf: 'stretch'}}>
<Text style={{fontSize: 20, color: '#FFFFFF'}}>Submit</Text>
</TouchableOpacity>
</KeyboardAwareView>
Hope it hepls
You will definitely find this useful from
Keyboard aware scroll view Android issue
I really don't know why you have to add
"androidStatusBar": {
"backgroundColor": "#000000"
}
for KeyboardawareScrollview to work
Note:don't forget to restart the project without the last step it might not work
enjoy!
I faced the same problem when I was working on my side project, and I solved it after tweaking KeyboardAvoidingView somewhat.
I published my solution to npm, please give it a try and give me a feedback! Demo on iOS
Example Snippet
import React from 'react';
import { StyleSheet, TextInput } from 'react-native';
import KeyboardStickyView from 'rn-keyboard-sticky-view';
const KeyboardInput = (props) => {
const [value, setValue] = React.useState('');
return (
<KeyboardStickyView style={styles.keyboardView}>
<TextInput
value={value}
onChangeText={setValue}
onSubmitEditing={() => alert(value)}
placeholder="Write something..."
style={styles.input}
/>
</KeyboardStickyView>
);
}
const styles = StyleSheet.create({
keyboardView: { ... },
input: { ... }
});
export default KeyboardInput;
I based my solution of #basbase solution.
My issue with his solution that it makes the TextInput jumps up without any regard for my overall view.
That wasn't what I wanted in my case, so I did as he suggested but with a small modification
Just give the parent View styling like this:
<View
style={{
flex: 1,
bottom: keyboardOffset,
}}>
And it would work! the only issue is that if the keyboard is open and you scrolled down you would see the extra blank padding at the end of the screen.
android:launchMode="singleTask"
android:windowSoftInputMode="stateAlwaysHidden|adjustPan"
write these two lines in your android/app/src/main/AndroidManifest.xml
in activity tag
flexGrow: 1 is the key.
Use it like below:
<ScrollView contentContainerStyle={styles.container}>
<TextInput
label="Note"
value={currentContact.note}
onChangeText={(text) => setAttribute("note", text)}
/>
</ScrollView>
const styles = StyleSheet.create({
container: {
flexGrow: 1,
},
});
Best and Easy Way is to use Scroll View , It will Automatically take content Up and TextInput will not be hide,Can refer Below Code
<ScrollView style={styles.container}>
<View>
<View style={styles.commonView}>
<Image source={firstNameIcon} style={{width: 25, height: 25}}></Image>
<Text style={styles.commonTxt}>First Name</Text>
</View>
<TextInput
onFocus={() => onFocus('firstName')}
placeholder="First Name"
style={styles.txtInput}
onChangeText={(text) => onChangeText(text, 'firstName')}
value={firstNameValue}
/>
</View>
<View>
<View style={styles.commonView}>
<Image source={LastNameIcon} style={{width: 25, height: 25}}></Image>
<Text style={styles.commonTxt}>Last Name</Text>
</View>
<TextInput
onFocus={() => onFocus('lastName')}
placeholder="Last Name"
style={styles.txtInput}
onChangeText={(text) => onChangeText(text, 'lastName')}
value={lastNameValue}
/>
</View>
<View>
<View style={styles.commonView}>
<Image source={callIcon} style={{width: 25, height: 25}}></Image>
<Text style={styles.commonTxt}>Number</Text>
</View>
<TextInput
onFocus={() => onFocus('number')}
placeholder="Number"
style={styles.txtInput}
onChangeText={(text) => onChangeText(text, 'number')}
value={numberValue}
/>
</View>
<View>
<View style={styles.commonView}>
<Image source={emailIcon} style={{width: 25, height: 25}}></Image>
<Text style={styles.commonTxt}>Email</Text>
</View>
<TextInput
onFocus={() => onFocus('email')}
placeholder="Email"
style={styles.txtInput}
onChangeText={(text) => onChangeText(text, 'email')}
value={emailValue}
/>
</View>
<View style={styles.viewSavebtn}>
<TouchableOpacity style={styles.btn}>
<Text style={styles.saveTxt}>Save</Text>
</TouchableOpacity>
</View>
</ScrollView>
go to your Android>app>src>main> AndroidManifest.xml
write these 2 lines :
android:launchMode="singleTop" android:windowSoftInputMode="adjustPan"

Double Tap Button issue when keyBoard opens React native

I know there are already so many queries on this topic, I have tried every step but still won't be able to fix the issue.
Here is the code :
render() {
const {sContainer, sSearchBar} = styles;
if (this.props.InviteState.objectForDeleteList){
this.updateList(this.props.InviteState.objectForDeleteList);
}
return (
<View style={styles.mainContainer}>
<CustomNavBar
onBackPress={() => this.props.navigation.goBack()}
/>
<View
style={sContainer}
>
<ScrollView keyboardShouldPersistTaps="always">
<TextInput
underlineColorAndroid={'transparent'}
placeholder={'Search'}
placeholderTextColor={'white'}
selectionColor={Color.colorPrimaryDark}
style={sSearchBar}
onChangeText={(searchTerm) => this.setState({searchTerm})}
/>
</ScrollView>
{this.renderInviteUserList()}
</View>
</View>
);
}
renderInviteUserList() {
if (this.props.InviteState.inviteUsers.length > 0) {
return (
<SearchableFlatlist
searchProperty={'fullName'}
searchTerm={this.state.searchTerm}
data={this.props.InviteState.inviteUsers}
containerStyle={styles.listStyle}
renderItem={({item}) => this.renderItem(item)}
keyExtractor={(item) => item.id}
/>
);
}
return (
<View style={styles.emptyListContainer}>
<Text style={styles.noUserFoundText}>
{this.props.InviteState.noInviteUserFound}
</Text>
</View>
);
}
renderItem(item) {
return (
this.state.userData && this.state.userData.id !== item.id
?
<TouchableOpacity
style={styles.itemContainer}
onPress={() => this.onSelectUser(item)}>
<View style={styles.itemSubContainer}>
<Avatar
medium
rounded
source={
item.imageUrl === ''
? require('../../assets/user_image.png')
: {uri: item.imageUrl}
}
onPress={() => console.log('Works!')}
activeOpacity={0.7}
/>
<View style={styles.userNameContainer}>
<Text style={styles.userNameText} numberOfLines={1}>
{item.fullName}
</Text>
</View>
<CustomButton
style={{
flexWrap: 'wrap',
alignSelf: 'flex-end',
marginTop: 10,
marginBottom: 10,
width: 90,
}}
showIcon={false}
btnText={'Add'}
onPress={() => this.onClickSendInvitation(item)}
/>
</View>
</TouchableOpacity> : null
);
}
**I even tried with bellow code as suggested by #Nirmalsinh **:
<ScrollView keyboardShouldPersistTaps="always" style={sContainer}>
<CustomNavBar
onBackPress={() => this.props.navigation.goBack()}
/>
<TextInput underlineColorAndroid={'transparent'}
placeholder={'Search'}
placeholderTextColor={'white'}
selectionColor={Color.colorPrimaryDark}
style={sSearchBar}
onChangeText={(searchTerm) => this.setState({searchTerm})} />
{this.renderInviteUserList()}
</ScrollView>
I have followed this article:
https://medium.com/react-native-training/todays-react-native-tip-keyboard-issues-in-scrollview-8cfbeb92995b
I have tried with keyboardShouldPersistTaps=handled also but still, I have to tap twice on my Custom Button to perform an action. Can anybody tell me what I am doing wrong inside the code?
Thanks.
You need to add give value always in keyboardShouldPersistTaps to allow user tap without closing the keyboard.
keyboardShouldPersistTaps='always'
For example:
<ScrollView keyboardShouldPersistTaps='always'>
// Put your component
</ScrollView>
NOTE: Kindly put your tappable component inside the ScrollView. Otherwise it won't work.
You can use keyboardShouldPersistTaps='handled' in a ScrollView or Scrollables like FlatList SectionList etc. and embed a TouchableWithoutFeedBack to handle the case for dismiss on outside clicks.
<TouchableWithoutFeedback onPress={Keyboard.dismiss}>
<ScrollView keyboardShouldPersistTaps='handled'>
// Rest of the content.
</ScrollView/>
</TouchableWithoutFeedback>
For FlatList and SectionList you will have to handle KeyBoard.dismiss separately.
Please try this, It's working for me, it will works you also, i hope it helps...