FlatList renderItem에 대한 고찰 [ReactNative]

진도리·2022년 2월 16일

ETC

목록 보기
1/1
post-thumbnail

Todo

  • 사용자들이 가려고 하거나 관심 있는 나라에 대한 정보를 얻기 위해 나라를 선택하는 시나리오에서 어떤 방식으로 나라를 선택하는 기능을 구현할지 고민했다.

  • 단순히 Grid 형식으로 약 200여 개의 나라 아이템들을 배치하여 하나의 나라를 터치하면 그 나라에 대한 정보를 제공하고, 그리드에 사용될 리스트를 나열할 때 ReactNative의 기본 컴포넌트인 FlatList를 사용했다.

FlatList는 많은 양의 리스트 아이템을 스크롤 형식으로 보여주고자 할 때 사용하는 컴포넌트로, 한 번에 리스트들의 모든 아이템을 렌더링 하지 않고 화면에 보이는 부분만을 렌더링할 때 사용됨.


Process


1. Failed.js

실제 코드에서 필요한 부분만

import React from 'react';
import { View, FlatList } from 'react-native';
import { Nations } from '../data/dummy-data'; // 약 200여개의 나라 아이템객체 (각 객체는 '나라 이름, iso 코드, 국기 이미지' 의  데이터를 담고있음)
import TouchableTab from './TouchableTab'; // 아이템을 터치하면 해당하는 나라의 정보를 제공하는 화면으로 갈 수 있도록하는 컴포넌트
 
const NationGrid = props => {
    return (
        <FlatList
            data={Nations} // 리스트 데이터
            renderItem={({ item }) => ( // nationList의 각 요소(item)마다 아래 <View/> 형식으로 렌더링함
                <View>
                    <TouchableTab
                    selectedNation={item}
                    onSelect={() => props.navigateToInfo(item)} // 정보 제공화면으로 이동
                    />
                </View>
            )}
            numColumns={3} // 행 하나에 렌더링할 아이템 개수 3개
        />
    )
}

🚨 위 코드로 앱을 빌드했더니 문제가 발생했다!

  • 발생한 문제
    FlatList가 아이템을 렌더링 할 때 0 ~ 29번째 아이템 렌더링 -> 0 ~ 59번째 아이템 렌더링 -> ... 이런식으로 30개의 아이템을 추가로 생성할 때마다 도돌이표로 돌아가듯이 처음부터 다시 아이템 렌더링이 반복되었다. 이로인해 화면 렌더링 시간이 느려지고 스크롤의 버벅임도 심해졌다.
                  
  • 어떻게 해결할지..?
    나라선택을 위한 기능을 어떻게 구현할지에 대한 접근 방법을 달리 해볼까 하는 생각을 하게되었다. 사용자들에게 모든 나라를 보여주는 것이 아닌 필요한 나라만을 보여주도록 해서 FlatList가 렌더링하는 아이템의 수를 줄이고자 했고 이것을 '검색기능'을 통해 구현했다.
    검색하는 text가 변경될 때마다 해당 text로 시작하는 나라명을 가진 나라들만을 FlatList로 화면에 보여주도록 코드를 구성했다.


2. solved.js

import { View, FlatList } from 'react-native';
import { SearchBar } from 'react-native-elements'; // 검색기능 라이브러리
import { Nations } from '../data/dummy-data';
import TouchableTab from './TouchableTab';
const SearchComponent = props => {
    const [query, setQuery] = useState(''); // 컴포넌트를 업데이트할 트리거로 사용될 query
    const [filteredNationList, setFilteredNationList] = useState([]); // 필터링된 리스트로 사용하기위한 filteredNationList
    useEffect(() => { // 첫 렌더링 시에만 filteredNationList에 Nations 값을 할당하기 위해 useEffect()를 사용
        setFilteredNationList(Nations.slice());
    }, []) // [value] 일 경우 'value' 가 업데이트 될 경우에만 useEffect()를 call / [] 처럼 아무것도 없을 시 해당 컴포넌트 최초 렌더링 시에만 call / 필터링을 통해filteredNationList 값이 변경되어 컴포넌트가 업데이트 되더라도 다시setFilteredNationList(Nations.slice()) 가 호출되지 않음
const updateQuery = (text) => {
        if (text) { // text 값이 존재할 경우
            let nationList = Nations.filter(function (item) {
                return item.nation.startsWith(text, 0) === true;
            })
            setFilteredNationList(nationList);
            setQuery(text); // query 값에 text를 할당하여 query 값이 변경되면 컴포넌트가 업데이트됨
        } else {
            setFilteredNationList(Nations.slice()); // text 값이 공백이면 다시 filteredNationList 에 전체 Nations 정보를 할당
            setQuery(text);
        }
    }
    const renderFilteredItem = (itemData) => {
        if (!query) return; // query 값이 없으면 아무것도 렌더링 하지 않음
        const country = itemData.item;
        return (
            <TouchableTab
                selectedNation={country}
                onSelect={() => props.navigateToInfo(country)}
            />
        )
    }
    return (
        <View>
            <SearchBar
                onChangeText={updateQuery} // text 값이 변경될 때마다 call updateQuery()
                value={query}
            />
           <FlatList
                data={filteredNationList} // 필터링된 아이템만을 보여줌
                renderItem={renderFilteredItem} // 아이템마다 renderFilteredItem() 의 절차를 따라 렌더링
            />
        </View>
    )
}
                  
  1. 예를 들어 검색창에 '아' 를 작성한다면, '' -> 'ㅇ' -> '아' 로 총 2번 업데이트된다. 처음엔 공백이라 query가 Falsy 값을 가지므로 아무것도 렌더링 되지 않는다.

  2. 다음엔 'ㅇ' 로 시작하는 나라 이름은 없기에 필터링을 통해 빈 리스트가 filteredNationList 에 할당되므로 역시 아무것도 렌더링 되지 않는다.

  3. 마지막으로 '아' 로 시작하는 나라 이름을 필터링하면 [아프가니스탄, 아랍에미리트, 아르헨티나, 아루바, 아이티, 아르메니아, 아제르바이잔, 아이슬란드, 아일랜드]가 filtereddNationList 에 할당되어 총 9개의 아이템이 FlatList를 통해 렌더링 된다.



Conclusion


1. Improvement

  • 검색 text로 필터링 된 리스트들만을 렌더링하기에 FlatList로 생성할 item들의 수가 크게 줄어들어 도돌이표처럼 반복해서 아이템을 생성하는 문제는 더 이상 발생하지 않았다.

  • 컴포넌트를 렌더링하는 시간과 스크롤의 버벅임이 개선되었다.



2. TakeAway

  • 개발 도중 문제가 발생했을 때 문제에 대한 접근 방법을 달리하여 문제가 해결되는 경우도 존재함

  • 내가 사용했던 리스트 데이터는 전 세계 나라에 대한 데이터로 약 200여 개의 정적인 데이터였고, 필터링으로 많은 데이터가 걸러졌기에 위처럼 해결할 수 있었음

  • 하지만 필터링을 해도 수백 가지가 되는 데이터를 FlatList로 렌더링 해야 했다면 FlatList의 Attributes를 제대로 숙지하는 것이 필요할 듯




"react": "17.0.1"
"react-native": "0.64.0"

profile
매일 작은 보폭이라도 앞으로.

0개의 댓글