- react-query로 flatlist에 무한 스크롤 구현 : react-query-infinite-flatlist-exampleGithubreact-query-infinite-flatlist-exampleOwnererdalstkUpdatedJul 14, 2021
무한 스크롤 핵심 키워드
주요 키워드 : getData 함수, 페이지 번호 state, onEndReached 함수
- useEffect()로 맨 처음에 마운트 됐을 때 getData를 호출하고, page state +1
- 스크롤이 끝에 도달했을 때 onEndReached() 함수가 호출되며 무한 스크롤을 구현하는 방식
- page state +1
- getData 함수 호출
<FlatList data={this.state.data} renderItem={this._renderItem} keyExtractor={(item, index) => item.id} onEndReached={this._handleLoadMore} onEndReachedThreshold={1} />
전체 코드 예시 (단순 axios)
그냥
axios
만 쓸 경우 캐시 기능이 없어서 요청을 많이 보낼 수도 있다.import React, {useState} from 'react'; import { View, Text, FlatList, Image, Dimensions, StyleSheet, TouchableOpacity, } from 'react-native'; import axios from 'axios'; import {NYTKey, NYTSearchURL, NYTBaseURL} from '@assets/NYTKey'; import {useEffect} from 'react'; export function ArticleScroll({query}: {query: string}) { const [page, setPage] = useState(0); const [data, setData] = useState([]); const getData = async () => { try { const docs = await axios .get(NYTSearchURL, { params: { 'api-key': NYTKey, q: query, sort: 'newest', page, }, }) .then(res => res.data.response.docs); console.log('검색 결과 : ', docs); console.log('page : ', page); setPage(page + 1); docs && setData(data.concat(docs)); } catch (e) { console.log('getData 실패', e); // 429라면 너무 많은 요청으로 인해 입력이 제한되었습니다. 알림 띄우기 } }; // 쿼리 변경 시 마다 상태 초기화 useEffect(() => { setPage(0); setData([]); }, [query]); useEffect(() => { if (page === 0) getData(); }, [page]); return ( // <View style={{flex: 1, backgroundColor: 'yellow'}}> <FlatList renderItem={Article} data={data} onEndReached={getData} onEndReachedThreshold={1} /> // </View> ); } const Article = ({item}) => { const supserJumbo = item.multimedia.find(mtmd => mtmd.subtype === 'jumbo'); console.log('Jumbo : ', supserJumbo); return ( <TouchableOpacity style={styles.articleRootContainer}> {supserJumbo && ( <Image source={{uri: `${NYTBaseURL}/${supserJumbo.url}`}} style={styles.jumboImage} /> )} <View style={styles.contentContainer}> <Text>{item.headline.main}</Text> <Text>{item.pub_date}</Text> </View> </TouchableOpacity> ); }; const styles = StyleSheet.create({ articleRootContainer: { flexDirection: 'row', width: '100%', marginBottom: 5, backgroundColor: 'lightgrey', }, jumboImage: {height: Dimensions.get('screen').width * 0.3, width: '30%'}, contentContainer: { flex: 1, borderBottomWidth: 1, width: '100%', padding: 10, }, });