https://youtu.be/Jc2MX0Ew3PE
microcode님의 리액트 네이티브 강의입니다. 이분은 말 한마디 없이 코딩만 하네요.
React Native에서 제공하는 FlatList
를 사용하여 무한 스크롤(Infinite Scroll)과 Pull Down Refresh 기능을 구현합니다. FlatList에 대한 자세한 내용은 공식 문서에서 확인하세요.
이번 예제를 위해서 snack를 이용하였습니다. 아래 화면처럼 브라우저에서 코딩하고 결과를 바로 확인 할 수 있습니다. 간단한 코딩 연습을 하기에 좋은 플랫폼입니다.
![]()
샘플 컴포넌트 생성하기
App.js
파일을 수정합니다. FlatList
의 data 속성에는 배열 데이터를 입력합니다. 그리고 renderItem 속성에는 렌더링 함수를 입력합니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| import React from 'react'; import { View, Image, Text, FlatList, } from 'react-native';
export default class App extends React.Component {
state = { data: [1, 2, 3] }
_renderItem = ({item}) => ( <Text>{item}</Text> );
render() { return ( <FlatList data={this.state.data} renderItem={this._renderItem} /> ); } }
|
아래는 결과화면입니다.
![]()
Fake Online REST API
우리는 이번 예제를 위해서 JSONPlaceholder에서 제공하는 Fake Online REST API를 사용할 것입니다. JSONPlaceholder에서는 아래와 같이 다양한 샘플 API를 제공하고 있습니다.
![]()
이중에서 /photos
API를 사용해 보겠습니다. JSON 데이터 형태는 아래와 같습니다.
![]()
서버에서 데이터 가져와서 출력하기
REST API에서 데이터를 가져오는 함수를 입력합니다. 한번에 10개씩 가져옵니다.
1 2 3 4 5 6 7 8 9 10
| _getData = async () => { const url = 'https://jsonplaceholder.typicode.com/photos?_limit=10'; fetch(url) .then(res => res.json()) .then(json => { this.setState({ data: json }); }); }
|
그리고 컴포넌트가 마운트되고 나서 호출되도록 합니다.
1 2 3
| componentDidMount() { this._getData(); }
|
마지막으로 _renderItem
함수를 수정합니다.
1 2 3 4 5 6
| _renderItem = ({item}) => ( <View style={{borderBottomWidth:1, marginTop: 20}}> <Image source={{ uri: item.url }} style={{ height: 200}} /> <Text>{item.title}</Text> </View> );
|
> 여기까지 작업한 전체 코드입니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| import React from 'react'; import { View, Image, Text, FlatList, } from 'react-native';
export default class App extends React.Component {
state = { data: [1, 2, 3] }
_getData = async () => { const url = 'https://jsonplaceholder.typicode.com/photos?_limit=10'; fetch(url) .then(res => res.json()) .then(json => { this.setState({ data: json }); }); }
componentDidMount() { this._getData(); }
_renderItem = ({item}) => ( <View style={{borderBottomWidth:1, marginTop: 20}}> <Image source={{ uri: item.url }} style={{ height: 200}} /> <Text>{item.title}</Text> </View> );
render() { return ( <FlatList data={this.state.data} renderItem={this._renderItem} keyExtractor={(item, index) => item.id} /> ); } }
|
그리고 결과 화면입니다.
![]()
무한 스크롤 구현하기
맨 아래 항목까지 스크롤되면, 다음 데이터를 자동으로 가져와서 목록에 추가하는 기능을 구현할 것입니다… 이 기능을 Infinite Scroll 또는 무한 스크롤이라고 합니다.
state
에 page
변수를 추가합니다.
1 2 3 4
| state = { data: [], page: 1 // here }
|
그리고 _getData
함수를 수정합니다. 데이터를 가져올때마다 _page
번호를 증가합니다. 이렇게 하면 다음 요청에서는 다음 페이지의 데이터를 가져올 것입니다. 그리고 가져온 데이터를 기존 data
에 추가(concat)합니다.
1 2 3 4 5 6 7 8 9 10 11
| _getData = () => { const url = 'https://jsonplaceholder.typicode.com/photos?_limit=10&_page=' + this.state.page; fetch(url) .then(r => r.json()) .then(data => { this.setState({ data: this.state.data.concat(data), // 기존 data에 추가. page: this.state.page + 1 }) }); }
|
그리고 _handleLoadMore
함수를 입력합니다. 이 함수는 스크롤이 끝까지 도달했을때 호출됩니다.
1 2 3
| _handleLoadMore = () => { this._getData(); }
|
마지막으로 render
함수를 수정합니다.
1 2 3 4 5 6 7 8 9 10 11
| render() { return ( <FlatList data={this.state.data} renderItem={this._renderItem} keyExtractor={(item, index) => item.id} onEndReached={this._handleLoadMore} onEndReachedThreshold={1} /> ); }
|
> 다음은 전체 코드입니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| import React from 'react'; import { View, Image, Text, FlatList, } from 'react-native';
export default class App extends React.Component {
state = { data: [], page: 1 }
_renderItem = ({item}) => ( <View style={{borderBottomWidth:1, marginTop: 20}}> <Image source={{ uri: item.url }} style={{ height: 200}} /> <Text>{item.title}</Text> <Text>{item.id}</Text> </View> );
_getData = () => { const url = 'https://jsonplaceholder.typicode.com/photos?_limit=10&_page=' + this.state.page; fetch(url) .then(r => r.json()) .then(data => { this.setState({ data: this.state.data.concat(data), page: this.state.page + 1 }) }); }
componentDidMount() { this._getData(); }
_handleLoadMore = () => { this._getData(); }
render() { return ( <FlatList data={this.state.data} renderItem={this._renderItem} keyExtractor={(item, index) => item.id} onEndReached={this._handleLoadMore} onEndReachedThreshold={1} /> ); } }
|
다음은 결과 화면입니다. 스크롤이 끊임없이 됩니다.
![]()
Pull Down Refresh 구현하기
이제 마지막입니다.
state
에 refreshing
변수를 추가합니다. refreshing
는 데이터를 가져오는 중인지를 판단합니다.
1 2 3 4 5
| state = { data: [], page: 1, refreshing: false // here }
|
_handleRefresh
함수를 입력합니다. 이 함수는 화면을 Pull Down하면 호출될 것입니다. 데이터를 새로 가져올 것이기 때문에, page 번호를 1로 초기화해 줍니다.
1 2 3 4 5 6
| _handleRefresh = () => { this.setState({ refreshing: true, page: 1, }, this._getData); }
|
render
함수를 수정합니다. refreshing 속성과 onRefresh 속성을 추가하였습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13
| render() { return ( <FlatList data={this.state.data} renderItem={this._renderItem} keyExtractor={(item, index) => item.id} onEndReached={this._handleLoadMore} onEndReachedThreshold={1} refreshing={this.state.refreshing} onRefresh={this._handleRefresh} /> ); }
|
마지막으로 _getData
함수를 수정합니다. refreshing
가 true 일때는 가져온 데이터를 기존 데이터에 추가(concat)하지 않습니다.
1 2 3 4 5 6 7 8 9 10 11 12
| _getData = () => { const url = 'https://jsonplaceholder.typicode.com/photos?_limit=10&_page=' + this.state.page; fetch(url) .then(r => r.json()) .then(data => { this.setState({ data: this.state.refreshing?data:this.state.data.concat(data), page: this.state.page + 1, refreshing: false }) }); }
|
다음은 결과 화면입니다. 화면을 아래로 당기면 onRefresh
이벤트가 발생합니다. 새로고침 해도 같은 데이터를 가져오기 때문에 화면의 변화는 없네요.
![]()
예제에 사용한 코드는 여기에서 확인할 수 있습니다.
감사합니다.