Reputation: 868
I've got a screen with a ScrollView that has a refreshControl property. Turns out that when I refresh my screen, the whole content of the screen moves a few positions down. If I refresh again it keeps going down and so on.
This screenshots are taken right before refreshing and right after. As you see after refreshing some space was added on top of the screen. Why?
Here's what's inside my render function:
render() {
if(this.state.isLoading || this.state.user === null) {
// IF I PUT RETURN NULL HERE IT WORKS FINE,AND THE CONTENT DOESNT GO DOWN
return(<ScrollView contentContainerStyle={{alignItems: "center", flex: 1, justifyContent: 'center'}}>
<Spinner isVisible={true} size={100} type={'Pulse'} color={'#013773'}/>
<DropdownAlert ref={ref => this.dropDownAlertRef = ref} />
</ScrollView>);
}
else {
return (
<ScrollView
refreshControl={
<RefreshControl
refreshing={this.state.isLoading}
onRefresh={this._onRefresh.bind(this)}
/>
}>
<View style={styles.whiteContainer}>
<View style={{backgroundColor: colors.white,paddingVertical: 10, borderStyle: 'solid', borderColor: colors.black}}>
<Text style={{fontStyle: 'italic', fontWeight: 'bold', fontSize:20, marginLeft:20, color: colors.grey}}>
Mis donaciones
</Text>
</View>
{this.state.myDonations.length > 0 ?
<Carousel
ref={(c) => { this._carousel = c; }}
data={this.state.myDonations}
renderItem={this._renderDonation}
sliderWidth={SLIDER_WIDTH}
itemWidth={ITEM_WIDTH2}
inactiveSlideShift={0}
onSnapToItem={(index) => this.setState({ index })}
scrollInterpolator={scrollInterpolator}
slideInterpolatedStyle={animatedStyles}
useScrollView={true}
/>:
<Text style={{fontStyle: 'italic', alignSelf: 'center', fontWeight: 'bold', fontSize:20, marginTop:20, marginBottom: 40, color: colors.grey}}>
¡Nada para mostrar!
</Text>}
</View>
{this.state.user.category === "Voluntario" ?
<View style={styles.whiteContainer2}>
<View style={{backgroundColor: colors.white,paddingVertical:10, borderStyle: 'solid', borderColor: colors.black}}>
<Text style={{fontStyle: 'italic', fontWeight: 'bold', fontSize:20, marginLeft:20, color: colors.grey}}>
Mis entregas
</Text>
</View>
{this.state.myDeliveries.length > 0 ?
<Carousel
ref={(c) => { this._carousel = c; }}
data={this.state.myDeliveries}
renderItem={this._renderDelivery}
sliderWidth={SLIDER_WIDTH}
itemWidth={ITEM_WIDTH2}
inactiveSlideShift={0}
onSnapToItem={(index) => this.setState({ index })}
scrollInterpolator={scrollInterpolator}
slideInterpolatedStyle={animatedStyles}
useScrollView={true}
/> : <Text style={{fontStyle: 'italic', alignSelf: 'center', fontWeight: 'bold', fontSize:20, marginTop:20, marginBottom: 40, color: colors.grey}}>
¡Nada para mostrar!
</Text>}
</View>
: null}
<View style={styles.whiteContainer2}>
<View style={{backgroundColor: colors.white, paddingVertical:10, borderStyle: 'solid', borderColor: colors.black}}>
<Text style={{fontStyle: 'italic', fontWeight: 'bold', fontSize:20, marginLeft:20, color: colors.grey}}>
Pedidos
</Text>
</View>
{this.state.requests.length > 0 ?
<Carousel
ref={(c) => { this._carousel = c; }}
data={this.state.requests}
renderItem={this._renderRequest}
sliderWidth={SLIDER_WIDTH}
itemWidth={ITEM_WIDTH}
inactiveSlideShift={0}
onSnapToItem={(index) => this.setState({ index })}
scrollInterpolator={scrollInterpolator}
slideInterpolatedStyle={animatedStyles}
useScrollView={true}
/> : <Text style={{fontStyle: 'italic', alignSelf: 'center', fontWeight: 'bold', fontSize:20, marginTop:20, marginBottom: 40, color: colors.grey}}>
¡Nada para mostrar!
</Text>}
</View>
<DropdownAlert ref={ref => this.dropDownAlertRef = ref} />
</ScrollView>
);
}
}
_onRefresh looks like this:
_onRefresh = () => {
this.setState({
user: null,
isLoading: true
});
}
isLoading is later set on false when methods inside componentDidUpdate finish loading.
I'm importing RefreshControl and ScrollView from "react-native": "~0.61.4".
Update: As you see inside my render method I got an if-else statement. Turns out if I put return null instead of my spinner inside of the first block, the problem is solved. Why?
Upvotes: 3
Views: 1961
Reputation: 81
Never needed double render condition, just simply add key
. when key change its trigger to remount of ui and its simply fix
render() {
return(
<ScrollView
key={`${this.state.isRefreshing}`}
refreshControl={
<RefreshControl
refreshing={this.state.isRefreshing}
onRefresh={this._onRefresh.bind(this)}
/>
}>
...
</ScrollView>
);
}
Upvotes: 0
Reputation: 868
Ok, I found the issue. As you see I had a conditional if-else statement in my render method. Turns out I had to add RefreshControl to the ScrollView of the first block of the statement as well.
render() {
if(this.state.isLoading || this.state.user === null) {
return(
<ScrollView contentContainerStyle={{alignItems: "center", flex: 1, justifyContent: 'center'}}
refreshControl={
<RefreshControl
refreshing={false}
onRefresh={this._onRefresh.bind(this)}
/>
}>
...
</ScrollView>);
}
else {
return (
<ScrollView
refreshControl={
<RefreshControl
refreshing={this.state.isLoading}
onRefresh={this._onRefresh.bind(this)}
/>
}>
...
</ScrollView>
);
}
}
Upvotes: 2