Bird
Raised Fist0
React Nativemobile~20 mins

Pull-to-refresh in React Native - Mini App: Build & Ship

Choose your learning style10 modes available
Build: PullToRefreshScreen
A simple screen with a list of items that can be refreshed by pulling down from the top.
Target UI
-------------------------
| PullToRefreshScreen   |
-------------------------
| Item 1                |
| Item 2                |
| Item 3                |
| Item 4                |
| Item 5                |
|                       |
| Pull down to refresh  |
-------------------------
Display a vertical scrollable list of 5 items labeled 'Item 1' to 'Item 5'.
Implement pull-to-refresh gesture that triggers a refresh indicator.
When refreshed, update the list by appending ' - refreshed' to each item label.
Use React Native's RefreshControl component.
Ensure accessibility by adding appropriate accessibility labels.
Starter Code
React Native
import React, { useState } from 'react';
import { SafeAreaView, FlatList, Text, RefreshControl } from 'react-native';

export default function PullToRefreshScreen() {
  const [items, setItems] = useState([
    'Item 1',
    'Item 2',
    'Item 3',
    'Item 4',
    'Item 5'
  ]);
  const [refreshing, setRefreshing] = useState(false);

  // TODO: Add onRefresh function to update items

  return (
    <SafeAreaView style={{ flex: 1 }}>
      <FlatList
        data={items}
        keyExtractor={(item) => item}
        renderItem={({ item }) => <Text style={{ padding: 20 }}>{item}</Text>}
        refreshControl={
          <RefreshControl
            refreshing={refreshing}
            onRefresh={() => { /* TODO: Implement refresh logic */ }}
            accessibilityLabel="Pull to refresh list"
          />
        }
      />
    </SafeAreaView>
  );
}
Task 1
Solution
React Native
import React, { useState, useCallback } from 'react';
import { SafeAreaView, FlatList, Text, RefreshControl } from 'react-native';

export default function PullToRefreshScreen() {
  const [items, setItems] = useState([
    'Item 1',
    'Item 2',
    'Item 3',
    'Item 4',
    'Item 5'
  ]);
  const [refreshing, setRefreshing] = useState(false);

  const onRefresh = useCallback(() => {
    setRefreshing(true);
    setTimeout(() => {
      setItems((prevItems) => prevItems.map(item => item.includes(' - refreshed') ? item : item + ' - refreshed'));
      setRefreshing(false);
    }, 1000); // Simulate network request delay
  }, []);

  return (
    <SafeAreaView style={{ flex: 1 }}>
      <FlatList
        data={items}
        keyExtractor={(item) => item}
        renderItem={({ item }) => <Text style={{ padding: 20 }} accessibilityLabel={item}>{item}</Text>}
        refreshControl={
          <RefreshControl
            refreshing={refreshing}
            onRefresh={onRefresh}
            accessibilityLabel="Pull to refresh list"
          />
        }
      />
    </SafeAreaView>
  );
}

We use React Native's RefreshControl inside the FlatList to enable pull-to-refresh. The onRefresh function sets the refreshing state to true, simulates a delay with setTimeout to mimic a network call, then updates the list items by appending ' - refreshed' only once to each item. Finally, it sets refreshing to false to hide the spinner. Accessibility labels are added to the refresh control and each item for screen readers.

Final Result
Completed Screen
-------------------------
| PullToRefreshScreen   |
-------------------------
| Item 1 - refreshed     |
| Item 2 - refreshed     |
| Item 3 - refreshed     |
| Item 4 - refreshed     |
| Item 5 - refreshed     |
|                       |
| Pull down to refresh  |
-------------------------
User pulls down on the list to trigger the refresh spinner.
After about 1 second, the list items update to show ' - refreshed' appended.
The refresh spinner disappears.
Stretch Goal
Add a button that resets the list items back to their original labels without ' - refreshed'.
💡 Hint
Add a button below the list that when pressed calls setItems with the original array ['Item 1', 'Item 2', 'Item 3', 'Item 4', 'Item 5'].

Practice

(1/5)
1. What is the main purpose of using RefreshControl in a React Native app?
easy
A. To enable pull-to-refresh functionality in scrollable lists
B. To add animations to buttons
C. To handle navigation between screens
D. To style text components

Solution

  1. Step 1: Understand the role of RefreshControl

    RefreshControl is a component used inside scrollable views to provide pull-to-refresh behavior.
  2. Step 2: Identify its main purpose

    Its main purpose is to let users pull down on a list to trigger a refresh action, usually to update content.
  3. Final Answer:

    To enable pull-to-refresh functionality in scrollable lists -> Option A
  4. Quick Check:

    Pull-to-refresh = RefreshControl usage [OK]
Hint: RefreshControl is for pull-to-refresh in lists [OK]
Common Mistakes:
  • Confusing RefreshControl with navigation or styling
  • Thinking it adds animations to buttons
  • Using it outside scrollable components
2. Which of the following is the correct way to use RefreshControl inside a ScrollView?
easy
A.
B.
C. } />
D. } />

Solution

  1. Step 1: Recall correct RefreshControl usage

    The refreshControl prop expects a RefreshControl component with props refreshing and onRefresh.
  2. Step 2: Match correct syntax

    <ScrollView refreshControl={<RefreshControl refreshing={refreshing} onRefresh={onRefresh} />} /> correctly passes refreshing and onRefresh inside <RefreshControl /> as a JSX element.
  3. Final Answer:

    <ScrollView refreshControl={<RefreshControl refreshing={refreshing} onRefresh={onRefresh} />} /> -> Option D
  4. Quick Check:

    refreshControl prop = RefreshControl component with correct props [OK]
Hint: Use refreshControl prop with RefreshControl JSX [OK]
Common Mistakes:
  • Passing props directly to ScrollView instead of RefreshControl
  • Calling RefreshControl as a function instead of JSX
  • Using wrong prop names like refresh or refreshHandler
3. Given this code snippet, what will happen when the user pulls down the list?
const [refreshing, setRefreshing] = React.useState(false);

const onRefresh = React.useCallback(() => {
  setRefreshing(true);
  setTimeout(() => setRefreshing(false), 2000);
}, []);

return (
  <ScrollView refreshControl={
    <RefreshControl refreshing={refreshing} onRefresh={onRefresh} />
  }>
    <Text>Pull down to refresh</Text>
  </ScrollView>
);
medium
A. The spinner never shows because refreshing is false
B. The spinner shows for 2 seconds, then hides automatically
C. The spinner shows indefinitely and never hides
D. The app crashes due to missing dependencies

Solution

  1. Step 1: Understand the refreshing state changes

    When the user pulls down, onRefresh sets refreshing to true, showing the spinner.
  2. Step 2: Analyze the timeout effect

    After 2 seconds, setRefreshing(false) hides the spinner automatically.
  3. Final Answer:

    The spinner shows for 2 seconds, then hides automatically -> Option B
  4. Quick Check:

    refreshing true then false after timeout = spinner shows then hides [OK]
Hint: Refreshing true shows spinner; false hides it [OK]
Common Mistakes:
  • Assuming spinner never hides without manual reset
  • Thinking refreshing starts as true initially
  • Confusing useCallback dependencies causing crashes
4. Identify the error in this pull-to-refresh implementation:
const [refreshing, setRefreshing] = React.useState(false);

function onRefresh() {
  setRefreshing(true);
  fetchData();
  setRefreshing(false);
}

return (
  <FlatList
    data={data}
    refreshControl={<RefreshControl refreshing={refreshing} onRefresh={onRefresh} />}
    renderItem={({item}) => <Text>{item}</Text>}
  />
);
medium
A. onRefresh should be async but is not
B. refreshControl prop should be refreshControl (lowercase c)
C. setRefreshing(false) is called immediately, hiding spinner too soon
D. FlatList does not support RefreshControl

Solution

  1. Step 1: Check refreshing state timing

    The function calls setRefreshing(false) immediately after fetchData(), without waiting for data to load.
  2. Step 2: Understand spinner behavior

    This causes the spinner to hide right away, not showing the loading state properly.
  3. Final Answer:

    setRefreshing(false) is called immediately, hiding spinner too soon -> Option C
  4. Quick Check:

    Refreshing state must stay true until data loads [OK]
Hint: Keep refreshing true until data fetch completes [OK]
Common Mistakes:
  • Calling setRefreshing(false) too early
  • Misnaming refreshControl prop
  • Assuming FlatList can't use RefreshControl
5. You want to add pull-to-refresh to a SectionList that fetches new data asynchronously. Which approach correctly ensures the spinner shows during fetch and hides after completion?
const [refreshing, setRefreshing] = React.useState(false);

const onRefresh = async () => {
  // What goes here?
};
hard
A. setRefreshing(true); await fetchData(); setRefreshing(false);
B. await fetchData(); setRefreshing(true); setRefreshing(false);
C. setRefreshing(false); await fetchData(); setRefreshing(true);
D. setRefreshing(true); fetchData(); setRefreshing(false);

Solution

  1. Step 1: Set refreshing true before fetching

    Call setRefreshing(true) to show spinner before starting data fetch.
  2. Step 2: Await fetchData and then set refreshing false

    Use await fetchData() to wait for data, then call setRefreshing(false) to hide spinner after completion.
  3. Final Answer:

    setRefreshing(true); await fetchData(); setRefreshing(false); -> Option A
  4. Quick Check:

    Show spinner before await, hide after await [OK]
Hint: Set refreshing true before await, false after await [OK]
Common Mistakes:
  • Setting refreshing false before fetch completes
  • Not awaiting fetchData causing spinner to hide early
  • Switching order of setRefreshing calls
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard