728x90
반응형

이전 포스팅에서는 구글 파이어 베이스의 Cloud FireStore에

데이터를 추가하고 Storagedp 파일도 같이 저장하는 방법을 알아보았습니다 

 

더 자세한 내용은 아래의 포스팅을 참고하세요

 

 

2022.07.31 - [Server/Firebase] - React Native X Expo X 구글 파이어 베이스 Cloud Firestore 데이터 추가 및 이미지 추가 기능 구현

 

React Native X Expo X 구글 파이어 베이스 Cloud Firestore 데이터 추가 및 이미지 추가 기능 구현

이번에는 구글 파이어 베이스의 Cloud Firestore 데이터 추가 기능을 구현해보겠습니다  추가할 때 이미지도 같이 저장해보도록 하겠습니다 아래의 목차와 같이 진행하겠습니다 Storage 설정 및 폴더

tantangerine.tistory.com

 

무한 스크롤이란?

스크롤을 내릴 때 마지막 하단까지 내려오게 되면 정보를 다시 불러와서

그 정보를 마지막 하단 밑에 붙여주는 효과입니다.

그렇게 되면 사용자로 하여금 스크롤이 무한으로 내려가는 것처럼 느껴지게 되는 것입니다.

 

 

무한 스크롤의 장점은?

기존은 페이징 처리가 되어있어 다음 페이지를 보려면 계속 클릭을 해주어야 합니다.

그렇게 되면 흥미가 떨어질 경우 클릭을 하지 않아 사용자가 이탈하는 경우가 발생합니다.

하지만 스크롤을 내리는 것은 사용자 입장에서는 간단하게 정보를 불러올 수 있으며

스크롤을 내리는 행위로 끊임없이 정보를 노출하면서 사용자의 이탈을 막을 수 있습니다.

 

 

리액트 네이티브 FlatList 및 Firestore Database 무한 스크롤 구현 방법

 

아래의 공식문서를 확인하시면 flatList의 활용하는 방법을 확인하실 수 있습니다

더 상세한 정보를 알고 싶다면 링크를 클릭하시면 됩니다.

 

https://docs.expo.dev/versions/latest/react-native/flatlist/

 

FlatList - Expo Documentation

Expo is an open-source platform for making universal native apps for Android, iOS, and the web with JavaScript and React.

docs.expo.dev

 

ScrollView와 비슷하면서 다른 FlatList

 

 

아래의 코드를 구현해보았습니다

이제 그 속성에 대해서 하나하나 알아보도록 합시다

 

import React, { useState, useEffect } from 'react';
import {
  ActivityIndicator,
  StyleSheet,
  Image,
  View,
  FlatList,
  SafeAreaView,
  Alert,
} from 'react-native';
import { Col, Row, Grid } from 'react-native-easy-grid';
import {
  Container,
  Header,
  Content,
  Left,
  Icon,
  Right,
  Text,
  Button,
} from 'native-base';
import CardComponent from '../components/CardComponent';
import HeaderComponent from '../components/HeaderComponent';
import * as Animatable from 'react-native-animatable';
import { getData, getNextData } from '../config/firebaseApi';
const data = require('../data.json');
export default function MainPage({ navigation }) {
  const [data, setData] = useState([]);
  const [next, setNext] = useState(0);

  useEffect(() => {
    navigation.addListener('beforeRemove', (e) => {
      e.preventDefault();
    });
    readyData();
  }, []);
  const readyData = async () => {
    const data = await getData(setNext);
    setData(data);
  };
  console.log('다음:' + next);
  return (
    <Container>
      <HeaderComponent />
      {data.length == 0 ? (
        <ActivityIndicator size="large" />
      ) : (
        <FlatList
          data={data}
          ListHeaderComponent={() => {
            return (
              <Content style={{ marginTop: 30 }}>
                <Animatable.View
                  animation="pulse"
                  easing="ease-out"
                  iterationCount={3}
                  direction="alternate"
                >
                  <Grid style={styles.banner}>
                    <Col size={1} style={{ padding: 20 }}>
                      <Icon name="paper-plane" style={{ color: 'deeppink' }} />
                    </Col>
                    <Col size={6} style={{ padding: 15 }}>
                      <Text>이야기 하고 싶은 친구들에게</Text>
                      <Text style={{ fontWeight: '700' }}>
                        wegram을 전하세요
                      </Text>
                    </Col>
                  </Grid>
                </Animatable.View>

                <Grid style={{ padding: 20 }}>
                  <Text style={{ color: 'grey' }}>FROM THE DIARY</Text>
                </Grid>
              </Content>
            );
          }}
          onEndReachedThreshold={0.8}
          onEndReached={async () => {
            console.log('바닥 가까이 감: 리프레시');
            if(next > 0){
              let nextData = await getNextData(next, setNext);
              if (nextData == 0) {
                Alert.alert('더이상 글이 없어요!');
              } else {
                let newData = [...data, ...nextData];
                console.log(newData);
                await setData(newData);
              }
            }
          }}
          renderItem={(data) => {
            // console.log(data);
            return (
              <CardComponent navigation={navigation} content={data.item} />
            );
          }}
          numColumns={1}
          keyExtractor={(item) => item.date.toString()}
        />
      )}
    </Container>
  );
}

const styles = StyleSheet.create({
  banner: {
    backgroundColor: '#F6F6F6',
    height: 70,
    borderRadius: 10,
    width: '90%',
    alignSelf: 'center',
  },
});

 

ListHeaderComponent 속에는 컴포넌트를 삽입해서 

아래와 같은 부분을 정의할 수 있습니다

 

 

ListHeaderComponent
헤더 컴포넌트 정의하기

 

 

onEndReachedThreshold={0}은 제일 하단을 언제부터 감지할 것이냐라는 것입니다

0을 준다면 하단 끝까지 맞닿았을 때 감지하게 됩니다.

이 부분은 조금씩 변경해서 한번 테스트를 해보시길 바랍니다.

그리고 감지될 경우  onEndReached에 정의된 함수를 실행하게 됩니다.

keyExtractor속성은 데이터의 키값에 해당하는 값을 넘겨주시면 됩니다.

 

 

속성설명
속성설명

 

하단이 감지된다면 

onEndReached의 함수가 실행돼서

다음 데이터를 호출하여 무한 스크롤 효과를 적용합니다

 

그리고 그 getNextData는 구글 파이어 베이스의 cloud Storage의 기능을 사용합니다

 

export async function getNextData(nextDate, setNext) {
  try {
    console.log("불러올 다음 date: " + nextDate)
    let data = []
    const db = firebase.firestore();
    const next = db.collection('diary')
      .orderBy('date', 'desc')
      .startAfter(nextDate)
      .limit(5);
    const snapshot = await next.get();
    snapshot.docs.map((doc) => {
      console.log("[페이지네이션 Next]")
      doc.data()
      data.push(doc.data());
    });
    console.log(snapshot.docs.length)
    let last;
    if (snapshot.docs.length !== 0) {
      last = snapshot.docs[snapshot.docs.length - 1];
      setNext(last.data().date)
      return data
    } else {
      return 0
    }

  } catch (err) {
    console.log(err);
    return false;
  }
}

 

 

위의 코드를 본다면 .startAfter은 매개변수의 값의 기준으로 그다음의 정보를 불러옵니다.

그리고 last함수에 마지막 데이터를 저장해서 값을 setNext에 넣어줍니다.

그래서 함수를 다시 호출할 때 next값을 사용하여 계속 정보를 가져오게 됩니다.

 

React Native를 공부하기 위해 책으로 공부할까 아니면

강의를 들을까 하다 귀찮기도 하고 강의를 듣기로 하였습니다

책은 값이 싸기는 하지만 책을 보면서 하면 시간이 많이 걸리고

강의를 보면 강의료가 비싸긴 해도 1~2주에 끝날 수 있으니 선호하는 편입니다

 

그러던 중 스파르타 코딩 클럽을 찾았고

후기가 안 좋은 편이긴 하였으나

처음이라 어떤지 궁금하기도 했고

올해 초 이벤트를 하길래 결제를 했었습니다

이벤트가 아니면 너무 비싼 가격이라 하지 않으려고 했었죠

하지만 코드를 보면 리팩토링 해야 할게 너무나도 많았습니다

처음에는 고치면서 하려다가 새로운 코드를 강의마다 적용해야 해서

엎는 과정에서 시간 소요가 상당했습니다

 

그래서 중간에 포기하고 그냥 포스팅하면서 기능 위주로 보려고 하는데

조금 심한 경우가 많네요

이걸 초보자분들이 본다고 생각하니 조금 아찔하기도 합니다

 

if문에 두 개의 return이 있는 거 하며

onEndReached를 실행할 때마다 next값이 0인데도 계속 조회해오는 이상한 구조입니다

처음부터 setNext에 0을 할당해서 getNextData를 호출하지 않게 해야 하는 것이 더 중요한데 말이지요

 

강사분도 그렇게 경력이 많아 보이지도 않고요

다음에는 정말 좋은 강의를 소개하는 포스팅도 쓰도록 해보아야겠네요

 

아무튼 무한 스크롤 구현은 끝났습니다

다음에 이 앱 개발 플러스 프로젝트를 마치고

전체적으로 리팩토링을 하는 포스팅을 올리도록 하겠습니다

 

아무튼 오늘도 앱에 대한 이해도를 넓히기 위해  공부한 것은 보람이 있었다고 할 수 있겠네요

그럼 모든 분들도 보람 있는 하루가 되셨기를 바랍니다

그럼 다음 포스팅에서 뵙겠습니다

 

파이팅!

 

 

 

 

 

 

 

 

 

728x90
반응형

+ Recent posts

Powered by Tistory, Designed by wallel