Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refresh control indicator is not displayed on iOS #875

Open
1 of 2 tasks
PiotrBorowski opened this issue Jul 13, 2023 · 10 comments
Open
1 of 2 tasks

Refresh control indicator is not displayed on iOS #875

PiotrBorowski opened this issue Jul 13, 2023 · 10 comments
Labels
bug Something isn't working

Comments

@PiotrBorowski
Copy link

Current behavior

Refresh control is not visible when I navigate to ListScreen and refreshing was triggered when screen was mounted in useEffect as below:


const ListScreen = () => {
  const data = [{ x: 1 }, { x: 2 }, { x: 3 }, { x: 4 }];

  const [isRefreshing, setIsRefreshing] = useState(false);

  const refresh = () => {
    setIsRefreshing(true);

    setTimeout(() => {
      setIsRefreshing(false);
    }, 2000);
  };

  const renderItem = ({ item }) => (
    <View style={{ height: 100 }}>
      <Text>{item.x}</Text>
    </View>
  );

  useEffect(() => {
    refresh();
  }, []);

  return (
    <SafeAreaView style={{ flex: 1 }}>
      <FlashList
        data={data}
        renderItem={renderItem}
        refreshControl={<RefreshControl refreshing={isRefreshing} onRefresh={refresh} />}
        estimatedItemSize={100}
      />
    </SafeAreaView>
  );
});

Refresh control works fine when it is triggered by swipe and additionally refresh control is visible when I've added some timeout (like below) but it doesn't solve the issue:

  const refresh = () => {
    setTimeout(() => {
      setIsRefreshing(true);
   }, 500);

    setTimeout(() => {
      setIsRefreshing(false);
    }, 2000);
  };

Expected behavior

Refresh indicator should be displayed even if it was triggered immediately after screen mount

To Reproduce

https://snack.expo.dev/@piotrborowski/graceful-donut

Platform:

  • iOS
  • Android

Environment

1.4.0 but also doesn't work on 1.4.3

@PiotrBorowski PiotrBorowski added the bug Something isn't working label Jul 13, 2023
@ssarnot
Copy link

ssarnot commented Jul 31, 2023

Same issue here :(

@focux
Copy link

focux commented Oct 4, 2023

Same issue as well, did anyone find a workaround?

@Jackmekiss
Copy link

Same issue

@mateuszurbas
Copy link

Same issue :( any advice how to deal with this?

@janandaraj
Copy link

janandaraj commented Jan 23, 2024

i changed

tintColor

it worked now

refreshControl={
                        <RefreshControl
                          enabled={true}
                          tintColor="#fff"
                          refreshing={isLoading}
                          onRefresh={() => {
                            console.log('refreshed');
                          }}
                        />
                      }

@IanvanderGeest
Copy link

IanvanderGeest commented May 16, 2024

I've noticed this issue as well, but this is not the correct repository for the bugreport as this seems to me to be an issue with React Native itself.
For now I'll dump all information I have on this issue here, and will link to a more appropiate repo once I find/open the issue there.

Environment information:
Macbook Pro 14" 2023, M3 Pro 18gb, Sonoma 14.4

package.json (fresh generated project with npx react-native init
{
  "name": "RefreshControlTest",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "android": "react-native run-android",
    "ios": "react-native run-ios",
    "lint": "eslint .",
    "start": "react-native start",
    "test": "jest"
  },
  "dependencies": {
    "react": "18.2.0",
    "react-native": "0.74.1"
  },
  "devDependencies": {
    "@babel/core": "^7.20.0",
    "@babel/preset-env": "^7.20.0",
    "@babel/runtime": "^7.20.0",
    "@react-native/babel-preset": "0.74.83",
    "@react-native/eslint-config": "0.74.83",
    "@react-native/metro-config": "0.74.83",
    "@react-native/typescript-config": "0.74.83",
    "@types/react": "^18.2.6",
    "@types/react-test-renderer": "^18.0.0",
    "babel-jest": "^29.6.3",
    "eslint": "^8.19.0",
    "jest": "^29.6.3",
    "prettier": "2.8.8",
    "react-test-renderer": "18.2.0",
    "typescript": "5.0.4"
  },
  "engines": {
    "node": ">=18"
  },
  "packageManager": "[email protected]"
}

Can confirm the issue is as described by PiotrBorowski, when mounting the screen component and triggering a loading state through React.useEffect the UI will not show the RefreshControl, manually triggering this by pulling down to refresh will trigger UI updates and show the spinner correctly. Also confirmed this issue is only present on iOS.

Code for reproduction:

App.tsx

import React from 'react';
import {RefreshControl, SafeAreaView, ScrollView, Text} from 'react-native';

const App = () => {
  const [loading, setLoading] = React.useState(false);

  const onRefresh = () => {
    setLoading(true);

    setTimeout(() => {
      // Do something asynchronous
      // We'll mock this with a setTimeout
      setLoading(false);
    }, 2000);
  };

  React.useEffect(() => {
    onRefresh();
  }, []);

  console.log({loading});

  return (
    <SafeAreaView style={{flex: 1}}>
      <ScrollView
        refreshControl={
          <RefreshControl refreshing={loading} onRefresh={onRefresh} />
        }>
        <Text>Hello World</Text>
      </ScrollView>
    </SafeAreaView>
  );
};

export default App;
Screen.Recording.2024-05-16.at.15.17.19.mov

@IanvanderGeest
Copy link

IanvanderGeest commented May 16, 2024

For now you could add this workaround hook to your project, not ideal but it'll work.

useRefresh.ts

import React from 'react';

const useRefresh = (refreshFunc: () => void, ...deps: unknown[]) => {
  React.useEffect(() => {
    setTimeout(() => {
      refreshFunc();
    }, 100);
  }, [...deps]);
};

export default useRefresh;

This can be used as such in your components

App.tsx

import React from 'react';
import {RefreshControl, SafeAreaView, ScrollView, Text} from 'react-native';

import useRefresh from './useRefresh';

const App = () => {
  const [loading, setLoading] = React.useState(false);

  const onRefresh = () => {
    setLoading(true);

    setTimeout(() => {
      // Do something asynchronous
      // We'll mock this with a setTimeout
      setLoading(false);
    }, 2000);
  };

  useRefresh(onRefresh);

  console.log({loading});

  return (
    <SafeAreaView style={{flex: 1}}>
      <ScrollView
        refreshControl={
          <RefreshControl refreshing={loading} onRefresh={onRefresh} />
        }>
        <Text>Hello World</Text>
      </ScrollView>
    </SafeAreaView>
  );
};

export default App;

@lsarni
Copy link

lsarni commented Jul 16, 2024

We are having the same issue, and it does seem to be a react native problem facebook/react-native#35779

@ashwini-ksingh
Copy link

Working fine for me with recent unreleased fixes. (tested with 0.75.4)
facebook/react-native#46655
facebook/react-native#46628

@thoughtworks-tcaceres
Copy link

Facing this issue currently as well.
react native : 0.73.6
flashlist: 1.7.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

10 participants