React-Native FlatList에 대해 알아보자

이병수·2020년 8월 30일
11

React-Native

목록 보기
1/1
post-thumbnail
post-custom-banner

오늘은 React-Navtive FlatList에 대해 알아보자!

FlatList 컴포넌트란?

  • FlatList는 많은 양의 스크롤이 필요한 리스트 아이템을 보여주고자 할 때 쓰이는 리액트네이티브 컴포넌트이다

  • JS에서의 map 함수 역할과 비슷하나 더 많은 기능을 내포하고 있어 react-native에서 많이 쓰이는 컴포넌트이다.

Compare with ScrollView

  • RN에서 많은 양의 데이터를 출력 할 때 <ScrollView>와 함께 주로 사용되는데 사용용도에 차이점이 조금 있다.

<ScrollView> 는 데이터가 화면에 벗어났을 때 단순히 Scroll을 생성하여 사용자와의 상호작용(swipe)을 통해 벗어난 부분을 볼 수 있게 해주는 데이 목적이 있다

출력해야 하는 데이터가 고정적이고 많지 않을 때 간단하게 사용할 수 있는 컴포넌트

이에 반해<FlatList>는 더 많은 기능이 있다.ScrollView와 같이 데이터가 화면에 벗어났을 때도 Scroll을 생성하지만, 한 번에 모든 데이터를 렌더링하지 않고 화면에 보여지는 부분(혹은 설정한 수만큼의 데이터)만 렌더링한다는 차이가 있다.

그렇기에 데이터의 길이가 가변적이고, 데이터의 양을 예측할 수 없는 경우 (API를 통해 외부에서 크기를 알 수 없는 데이터를 가져오는 경우)에 사용하기 적절하다.

Basic Usage

  • FlatList를 사용하려면 두 가지 prop를 꼭 알아야 하는데 datarenderItem이다.
  • data는 만들고자 하는 리스트의 soucre를 담는 prop이다.
  • renderItemdata로 받은 소스들 그 각각의 item들을 render시켜주는 콜백함수이다.
  • keyExtractor 는 ReactJS map함수에서 key={idex} 와 해줬듯이 각각의 item에 고유의 키를 주는 것이라 생각하면 된다.
    ex) keyExtractor={(item, index) => index.toString()}

예제


const renderItem = ({ item }) => {
  return (
    <View>
      <View>
        <Text>user id: {item.userId}</Text>
      </View>
      <View>
        <Text>id: {item.id}</Text>
      </View>
      <View>
        <Text>title: {item.title}</Text>
      </View>
      <View>
        <Text>body: {item.body}</Text>
      </View>
    </View>
  );
};

const LIMIT = 11;

export default function App() {
  const [data, setData] = useState([]);
  const [offset, setOffset] = useState(0);
  const [loading, setLoading] = useState(false);

  const getData = () => {
    setLoading(true);
    fetch("http://jsonplaceholder.typicode.com/posts")
      .then((res) => res.json())
      .then((res) => setData(res))
  };

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

  
  return (
    <SafeAreaView style={styles.container}>
      <FlatList
        data={data}
        renderItem={renderItem}
        keyExtractor={(item) => String(item.id)}
      />
    </SafeAreaView>
  );
}

Pagenation

pagenation은 많은 양의 로드할 데이터가 앱에 있을 때 있어야할 다른 중요한 functionality이다.

  • 왜냐면 실제로 우리는 많은 양의 데이터를 한 번에 로드할 수 없기 때문이다. 그렇게 하면 우리의 앱은 느려질 뿐만 아니라 퍼포먼스와 UX적으로 비효율적(inefficient)으로 된다.

  • FlatList에서는 onEndReached를 통해 유저가 화면의 끝에 도달했을 때 새로운 데이터를 호출(fetch)하여 해당 비효율을 해결할 수 있게한다.

예제

const LIMIT = 11;

export default function App() {
  const [data, setData] = useState([]);
  const [offset, setOffset] = useState(0);
  const [loading, setLoading] = useState(false);

  const getData = () => {
    setLoading(true);
    fetch("http://jsonplaceholder.typicode.com/posts")
      .then((res) => res.json())
      .then((res) => setData(data.concat(res.slice(offset, offset + LIMIT))))
      .then(() => {
        setOffset(offset + LIMIT);
        setLoading(false);
      })
      .catch((error) => {
        setLoading(false);
        Alert.alert("에러가 났습니다");
      });
  };

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

  const onEndReached = () => {
    if (loading) {
      return;
    } else {
      getData();
    }
  };

여기서 if(loading) { return } 을 통해 로딩 중 계속 호출(fetch) 되는 것을 막는다.

 return (
   <SafeAreaView style={styles.container}>
     <FlatList
       data={data}
       renderItem={renderItem}
       keyExtractor={(item) => String(item.id)}
       onEndReached={onEndReached}
       onEndReachedThreshold={0.8}
       ListFooterComponent={loading && <ActivityIndicator />}
     />
   </SafeAreaView>
 );
}
  • 여기서 onEndReachedThreshold는 onEndReach의 지점을 설정해주는 것이라 할 보면 된다. 기본이 1이라고 한다면 제일 유저의 화면 끝에서 실행된다면 0.8은 해당 화면에서 80%가 됐을 때 실행된다고 보면된다.

  • <ActiveIndicator>는 아래와 같은 RN에서 제공하는 로딩 컴포넌트이다.

    const FlatListItemSeperator = () => {
       return (
         <View
           style={{
             height: 1,
             width: "100%",
             backgroundColor: "#000",
           }}
         />
       );
     };
  • ItemSeparatorComponent={FlatListItemSeperator} 을 통해 각 아이템 간의 커스텀을 줄 수도 있다

  • 또한 ListHeaderComponentListFooterComponent 활용해 header와 footer에 어떤 요소를 넣을지 커스텀/결정할 수 있다.

참고문서

post-custom-banner

0개의 댓글