더북(TheBook)

9.5.6 페이지네이션 구현하기

프로필 화면에서도 페이지네이션을 구현해봅시다. 포스트 목록 화면에서 구현한 방법과 동일합니다. 포스트를 조회하는 과정에서 userId 옵션이 추가될 뿐이죠.

components/Profile.js

(...)
import {
  (...)
  RefreshControl,
} from 'react-native';
import {getNewerPosts, getOlderPosts, getPosts, PAGE_SIZE} from '../lib/posts';

function Profile({userId}) {
  const [user, setUser] = useState(null);
  const [posts, setPosts] = useState(null);

  const [noMorePost, setNoMorePost] = useState(false);
  const [refreshing, setRefreshing] = useState(false);

  const onLoadMore = async () => {
    if (noMorePost || !posts || posts.length < PAGE_SIZE) {
      return;
    }
    const lastPost = posts[posts.length - 1];
    const olderPosts = await getOlderPosts(lastPost.id, userId);
    if (olderPosts.length < PAGE_SIZE) {
      setNoMorePost(true);
    }
    setPosts(posts.concat(olderPosts));
  };

  const onRefresh = async () => {
    if (!posts || posts.length === 0 || refreshing) {
      return;
    }
    const firstPost = posts[0];
    setRefreshing(true);
    const newerPosts = await getNewerPosts(firstPost.id, userId);
    setRefreshing(false);
    if (newerPosts.length === 0) {
      return;
    }
    setPosts(newerPosts.concat(posts));
  };

  useEffect(() => {
    getUser(userId).then(setUser);
    getPosts({userId}).then(setPosts);
  }, [userId]);

  if (!user || !posts) {
    return (
      <ActivityIndicator style={styles.spinner} size={32} color="#6200ee" />
    );
  }

  return (
    <FlatList
      style={styles.block}
      data={posts}
      renderItem={renderItem}
      numColumns={3}
      keyExtractor={(item) => item.id}
      ListHeaderComponent={
        <View style={styles.userInfo}>
          <Avatar source={user.photoURL && {uri: user.photoURL}} size={128} />
          <Text style={styles.username}>{user.displayName}</Text>
        </View>
      }
      onEndReached={onLoadMore}
      onEndReachedThreshold={0.25}
      ListFooterComponent={
        !noMorePost && (
          <ActivityIndicator
            style={styles.bottomSpinner}
            size={32}
            color="#6200ee"
          />
        )
      }
      refreshControl={
        <RefreshControl onRefresh={onRefresh} refreshing={refreshing} />
      }
    />
  );
}

const renderItem = ({item}) => <PostGridItem post={item} />;

const styles = StyleSheet.create({
  (...)
  bottomSpinner: {
    height: 128,
  }
});

export default Profile;

FeedScreen의 코드를 복사/붙여넣기한 수준으로 매우 비슷합니다. 차이점은 getNewerPostsgetOlderPostsuserId 파라미터를 넣고, onEndreachedthreshold0.25로 설정했다는 점입니다. 이 값을 낮춤으로써 화면의 끝에 더 가까워져야 다음 포스트를 불러오게 됩니다.

이제 화면에서 스크롤해보세요. 페이지네이션이 잘 이뤄지나요? 새 사진을 업로드하고 화면을 아래로 끌어당겨보세요. 새로운 사진이 잘 추가되나요?

신간 소식 구독하기
뉴스레터에 가입하시고 이메일로 신간 소식을 받아 보세요.