Updated April 17, 2019

Migrating from Component State to Hooks for a Fetch Request

Hooks are the latest hotness in React Native. Now that they're part of React Native core how can this change your code?

Starting Code

import React from 'react';
import {
  StyleSheet,
  Text,
  View,
  FlatList,
  SafeAreaView,
  ActivityIndicator,
  Button,
} from 'react-native';

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
});

export default class App extends React.Component {
  state = {
    people: [],
    loading: true,
    page: 1,
  };

  componentDidMount() {
    this.getPeople();
  }

  getPeople = () => {
    this.setState({ loading: true });
    fetch(`https://swapi.co/api/people?page=${this.state.page}`)
      .then((res) => res.json())
      .then((res) => {
        this.setState((state) => ({
          people: [...state.people, ...res.results],
          loading: false,
        }));
      });
  };

  render() {
    return (
      <SafeAreaView style={{ flex: 1 }}>
        <FlatList
          data={this.state.people}
          keyExtractor={(item) => item.url}
          renderItem={({ item }) => (
            <View>
              <Text>{item.name}</Text>
            </View>
          )}
          ListFooterComponent={
            this.state.loading ? (
              <ActivityIndicator />
            ) : (
              <Button
                title="Load More"
                onPress={() => {
                  this.setState(
                    (state) => ({ page: state.page + 1 }),
                    this.getPeople
                  );
                }}
              />
            )
          }
        />
      </SafeAreaView>
    );
  }
}

Finished Code

const useSwapiPeople = () => {
  const [people, setPeople] = useState([]);
  const [loading, setLoading] = useState(false);
  const [page, setPage] = useState(1);

  useEffect(() => {
    setLoading(true);
    fetch(`https://swapi.co/api/people?page=${page}`)
      .then((res) => res.json())
      .then((res) => {
        setPeople([...people, ...res.results]);
        setLoading(false);
      });
  }, [page]);

  const loadMore = () => {
    setPage(page + 1);
  };

  return {
    people,
    loading,
    loadMore,
  };
};

export default () => {
  const { people, loading, loadMore } = useSwapiPeople();

  return (
    <SafeAreaView style={{ flex: 1 }}>
      <FlatList
        data={people}
        keyExtractor={(item) => item.url}
        renderItem={({ item }) => (
          <View>
            <Text>{item.name}</Text>
          </View>
        )}
        ListFooterComponent={
          loading ? (
            <ActivityIndicator />
          ) : (
            <Button title="Load More" onPress={loadMore} />
          )
        }
      />
    </SafeAreaView>
  );
};
React Native School Logo

React Native School

Want to further level up as a React Native developer? Join React Native School! You'll get access to all of our courses and our private Slack community.

Learn More