React-native: RefreshControl does not work correctly on state change

Created on 14 May 2019  路  22Comments  路  Source: facebook/react-native

React Native version:
0.59.8

Steps To Reproduce

  1. Pull down on list, refresh control appears (as it should)
  2. Press button on top of list to load data, refresh control does not appear even though refreshing is true. You can also this is true by pressing the button first, the pulling down, then finally pressing the button again.

Describe what you expected to happen: The refresh control should appear whenever refreshing is true

Snack, code example, or link to a repository: https://snack.expo.io/ByZXxOuhV

Bug RefreshControl

Most helpful comment

still an issue on v0.62.2 when <RefreshControl /> is enabled (with local state) from a useEffect function.

All 22 comments

Hey there, it looks like there has been no activity on this issue recently. Has the issue been fixed, or does it still require the community's attention? This issue may be closed if no further activity occurs. You may also label this issue as a "Discussion" or add it to the "Backlog" and I will leave it open. Thank you for your contributions.

This is still an issue

Problem stills on 0.60.4

Can confirm, it is really annoying because there are no actual workarounds if you need to:

  • Keep pull to refresh functionality
  • Show the loading indicator when the refresh is triggered programmatically (e.g. the user searched something)

I noticed it only happens on iOS (I tested on Android 9.0.0 and it works properly)

+1

Android works properly, while iOS does not. Somehow refreshing state doesn't keep on the screen while app is reloading and resets immediately.

+1

I have this issue too. RN version 0.59.8.

+1
0.60.4, it happens only in iOS with the controlled prop

+1 I also experience in RN 0.59.8 on IOS only

+1 ios
when I use react-navigation to customize the header, and set the navigation height by headerStyle, the problem appear, if I remove the header it's ok.

same issue ,why so much bugs in basic component馃檭馃檭馃檭馃檭馃檭馃檭馃檭馃檭馃檭馃檭馃檭馃檭馃檭馃檭馃檭馃檭馃檭馃檭馃檭馃檭馃檭馃檭馃檭馃檭

+1
RN 0.60.4, Same issue.
Doesn't work on iOS but works perfectly on Android.

I had to use a very hacky and very wrong workaround to make it work.

Basically, I noticed that it worked _the first time_ (usually while loading the initial data at screen startup) but stopped working after that. So, I force the component (a FlatList in my case) to re-render completely after each successful refreshcontrol appearance, by changing its key attribute.

Honestly, it sucks, and it could not be feasible on lists with a lot of components to re render, but in my case it works well enough.

export default class extends React.Component {
  flastListKey = 0

  constructor(props) {
    super(props)
    this.state = {
      loading: false
    }
  }

  render () {
    <FlatList
      key={this.flatListKey}
      refreshing={this.state.loading}
      onRefresh={() => this.refreshData()}
      {... other props}
      />
  }

  refreshData = () => {
    this.setLoading(true)

    // DO stuff

    setTimeout(() => {
      this.setLoading(false)
    }, 2000)
  }

  setLoading = (loading: boolean) => {
    let shouldResetFlatlist = this.state.loading && !loading

    this.setState(
      {
        loading: loading,
      },
      () => {
        if (shouldResetFlatlist) {
          this.resetFlatlist()
        }
      },
    )
  }

  resetFlatlist = () => {
    if (Platform.OS === 'ios') {
      this.flatListKey = Math.random() * 1000
      setTimeout(() => {
        this.forceUpdate()
      }, 250)
    }
  }
}

The timeout is necessary to wait for the RefreshControl animation to finish

+1
RN 0.61.2 failing as well. It doesn't work on iOS but works perfectly on Android.

+1
RN 0.61.2, Same issue.
thanks @gbalduzzi

+1
Still seeing this issue!

See my comment here for a possible workaround

Opened Pr ^

If anyone is still having problems with this:

I found a workaround that is just enabling the bounce.

I had bounces={false} and after removing it, it's working on iOS now(Android was already working)

But in my case, the loading didn't appear not even once.

still an issue with v0.61.4

still an issue on v0.62.2 when <RefreshControl /> is enabled (with local state) from a useEffect function.

Hey, guys, I am facing the same issue with android, please have a look at this code, don't know why it is not working
class Home extends Component { constructor(props) { super(props); this.state = { loading: false, lastLoadDate: null, onPullRefresh: false, postArray: [], allLoadDone: false, limit: 5, refreshing: false, }; this.onEndReachedCalledDuringMomentum = false; }

componentDidMount() { console.log( 'Component did mount Home.js retrieve data called', this.state.postArray, ); this.retrieveData(); }

 <View style={styles.listView}>
          <FlatList
            //data

            style={{width: '100%'}}
            data={this.state.postArray}
            extraData={this.state}
            //renderItems
            renderItem={({item}) => (
              <Post
                userName={item.userName}
                userPhoto={item.userPhotoURL}
                imageData={item.postImageURL}
                likes={item.likes}
                // id={item.}
                title={item.title}
                hashtags={item.hashtags}
                resizeMode={item.style}
                timeStamp={item.createdAt}
                navigation={this.props.navigation}
              />
            )}
            //Item Key
            keyExtractor={(item, index) => String(index)}
            //Footer loader
            ListFooterComponent={this.renderFooter}
            //on end reached

            onEndReached={() => {
              if (!this.onEndReachedCalledDuringMomentum) {
                // if (allLoadDone) {
                //   noRetrieve();
                // } else {
                this.retrieveMore();
                // }
              }
            }}
            onMomentumScrollBegin={() => {
              this.onEndReachedCalledDuringMomentum = false;
            }}
            refreshControl={
              <RefreshControl
                refreshing={this.state.onPullRefresh}
                colors={[PrimaryColor, SecondaryColor, 'white']}
                progressBackgroundColor="pink"
                onRefresh={this.retrieveData}
                enabled={true}

              />
            }
            // How Close To The End Of List Until Next Data Request Is Made
            onEndReachedThreshold={0.1}
            showsVerticalScrollIndicator={false} //hides the vertical scroll
            refreshing={this.state.refreshing}
          />
Was this page helpful?
0 / 5 - 0 ratings