리액트 네이티브는 페이스 북이 공개한 iOS와 안드로이드 앱 개발을 위한 라이브러리입니다. 이전 글에서 사용한 예제를 확장하여 Realm과 연동시키고 Realm 데이타베이스를 로컬 캐쉬로 사용하는 예제로 만듭니다.
Realm 환경 설정
Realm을 리액트 네이티브에서 쓰기 위해서 간단한 설정이 필요합니다. 먼저 프로젝트 경로로 이동하신 후 터미널에 다음과 같이 입력합니다.
npm install --save realm
구체적인 추가 설정은 Ream 리액트 네이티브 문서를 참고하세요.
안드로이드 추가 설정
추가된 Realm 의존성을 연결시킵니다.
react-native link realm
android/app/src/main/java/com/awesomeproject/MainActivity.java
파일을 엽니다. 만약 프로젝트 명이 다르면 awesomeproject
대신 다른 경로로 들어갑니다.
다른 import
문들 아래에 아래를 추가합니다.
import io.realm.react.RealmReactPackage;
getPackages()
메서드를 찾아 반환 리스트에 다음을 추가합니다.
iOS 추가 설정
프로젝트 파일을 엽니다.
open ios/AwesomeProject.xcodeproj/
AwesomeProject
경로는 프로젝트 설정에 따라 다를 수 있습니다.
사이드바에 top-level project가 선택됐는지 확인하고, 프로젝트 설정에서 iOS 배포 타겟을 최소한 8.0으로 변경합니다.
사이드바의 Libraries 그룹을 우클릭하고 Add Files to “
앱 타겟 설정의 General 탭을 엽니다. 왼쪽 컬럼에서 Libraries > RealmJS > Products를 확장하고 앱 타겟 설정을 위해 RealmReact.framework을 긁어서 General 탭의 Embedded Binaries 섹션으로 옮깁니다.
리액트 네이티브와 Realm을 같이 쓰기
그 다음으로는 에디터에서 index.android.js
나 index.ios.js
를 수정합시다. 수정할 파일은 전적으로 어떤 운영체제를 사용하냐에 달려있습니다. 안드로이드를 사용하는 경우엔 전자를 수정하고 아이폰을 가지고 있는 경우 후자를 수정합시다. 저는 index.android.js
를 수정하겠습니다.
필요한 파일을 열고 다음과 같은 코드를 상단에 넣어줍니다.
const Realm = require('realm');
스키마 정의와 초기화
스키마를 다음과 같이 추가합니다.
const PosterSchema = {
name: 'Poster',
properties: {
thumbnail: 'string',
}
};
const MovieSchema = {
name: 'Movie',
properties: {
title: 'string',
year: 'int',
posters: 'Poster',
}
};
다른 프로퍼티들은 정의하지 않고 현재 사용하는 title
, year
, posters.thumbnail
만 정의하였습니다.
두개의 스키마를 전달하여 Realm 인스턴스를 생성합시다.
var realm = new Realm({schema:[PosterSchema, MovieSchema]});
캐쉬를 추가한 fetchData
fetchData() {
if (realm.objects('Movie').length > 0) {
this.setState({
dataSource: this.state.dataSource.cloneWithRows(realm.objects('Movie')),
loaded: true,
})
return;
}
fetch(REQUEST_URL)
.then((response) => response.json())
.then((responseData) => {
this.setState({
dataSource: this.state.dataSource.cloneWithRows(responseData.movies),
loaded: true,
});
for (var i in responseData.movies) {
realm.write(() => {
let posters = realm.create('Posters', {
thumbnail: responseData.movies[i].posters.thumbnail,
});
let movie = realm.create('Movie', {
title: responseData.movies[i].title,
year: responseData.movies[i].year,
posters: posters,
});
});
}
})
.done();
}
realm
인스턴스에 objects(<객체명>)
을 호출하면 객체를 전달받을 수 있습니다. 여기의 개수를 통해 캐슁이 되어 있는지를 판단하고 재사용하도록 합니다.
캐슁되지 않았다면 실제로 fetch(REQUEST_URL)
를 통해 서버에서 데이터를 가지고 오고 데이터를 가지고 온 이후 realm.write
의 블록에서 캐쉬로 저장을 합니다. realm.write
블록은 쓰기 트랜잭션을 여는 메서드입니다. Poseters
와 Movie
두개의 객체를 만들고 Posters
는 Movie
의 필드 posters
에 지정합니다.
전체 코드
전체 코드는 아래와 같습니다.
/**
* Sample React Native App
* https://github.com/facebook/react-native
*/
'use strict';
import React, {
AppRegistry,
Component,
Image,
ListView,
StyleSheet,
Text,
View
} from 'react-native';
const Realm = require('realm');
var MOCKED_MOVIES_DATA = [
{title: 'Title', year: '2015', posters: {thumbnail: 'http://i.imgur.com/UePbdph.jpg'}},
];
var REQUEST_URL =
'https://raw.githubusercontent.com/facebook/react-native/master/docs/MoviesExample.json';
const PostersSchema = {
name: 'Posters',
properties: {
thumbnail: 'string',
}
};
const MovieSchema = {
name: 'Movie',
properties: {
title: 'string',
year: 'int',
posters: 'Posters',
}
};
var realm = new Realm({schema:[PostersSchema, MovieSchema]});
class AwesomeProject extends Component {
constructor(props) {
super(props);
this.state = {
dataSource: new ListView.DataSource({
rowHasChanged: (row1, row2) => row1 !== row2,
}),
loaded: false,
};
}
componentDidMount() {
this.fetchData();
}
fetchData() {
if (realm.objects('Movie').length > 0) {
this.setState({
dataSource: this.state.dataSource.cloneWithRows(realm.objects('Movie')),
loaded: true,
})
return;
}
fetch(REQUEST_URL)
.then((response) => response.json())
.then((responseData) => {
this.setState({
dataSource: this.state.dataSource.cloneWithRows(responseData.movies),
loaded: true,
});
for (var i in responseData.movies) {
realm.write(() => {
let posters = realm.create('Posters', {
thumbnail: responseData.movies[i].posters.thumbnail,
});
let movie = realm.create('Movie', {
title: responseData.movies[i].title,
year: responseData.movies[i].year,
posters: posters,
});
});
}
})
.done();
}
render() {
if (!this.state.loaded) {
return this.renderLoadingView();
}
return (
<ListView
dataSource={this.state.dataSource}
renderRow={this.renderMovie}
style={styles.listView}
/>
);
}
renderLoadingView() {
return (
<View style={styles.container}>
<Text>
Loading movies...
</Text>
</View>
);
}
renderMovie(movie) {
return (
<View style={styles.container}>
<Image
source={{uri: movie.posters.thumbnail}}
style={styles.thumbnail}
/>
<View style={styles.rightContainer}>
<Text style={styles.title}>{movie.title}</Text>
<Text style={styles.year}>{movie.year}</Text>
</View>
</View>
);
}
}
var styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
thumbnail: {
width: 53,
height: 81,
},
rightContainer: {
flex: 1,
},
title: {
fontSize: 20,
marginBottom: 8,
textAlign: 'center',
},
year: {
textAlign: 'center',
},
listView: {
paddingTop: 20,
backgroundColor: '#F5FCFF',
},
});
AppRegistry.registerComponent('AwesomeProject', () => AwesomeProject);
튜토리얼을 마치며
여태까지 리액트 네이티브로 안드로이드와 iOS 앱을 동시에 개발하는 방법을 함께 알아봤습니다. 많은 코드를 작성하지 않고도 여러 운영체제에서 잘 작동하는 앱을 만들 수 있다는 점이 리액트 네이티브의 장점인 것 같습니다. 더 알아보고 싶은 분들을 위해 추가로 보면 좋을 자료를 공유하며 이번 튜토리얼을 마치겠습니다.
함께 쓰면 좋은 제품과 오픈소스 프로젝트
Realm 모바일 데이터베이스는 리액트 네이티브에서 사용할 수 있는 빠르고 간편한 객체형 데이터베이스입니다. 안드로이드와 iOS에서는 이미 널리 사용되고 있으며, 언제나 살아있는 객체로 최신의 데이터를 유지하면서 앱 모델 레이어를 정말 빠르게 작성하도록 도와줍니다. 리액트 네이티브 문서에서 단계별로 따라하면서 적용할 수 있습니다.
Realm 모바일 플랫폼은 더 나은 리액티브 앱 개발을 위해 백엔드 솔루션을 제공합니다. 특별히 관리하지 않아도 데이터가 실시간 동기화되므로 네트워크 연동을 위한 별도의 코딩을 하지 않아도 됩니다. 현재는 안드로이드와 iOS만을 지원하지만, 곧 리액트 네이티브를 지원한다고 하니 Realm 모바일 데이터베이스와 함께 연동하시면 시너지를 누릴 수 있을 겁니다.
영문이기는 하지만 FinanceReactNative에서 증권 정보를 보여주기 위해 서드파티 API를 활용하는 방법을 확인할 수 있습니다. 차트와 데이터를 다루는 법도 포함된 오픈소스 프로젝트로 해당 분야에 관심있는 분께 많은 도움이 될 겁니다.
또한 Build a Coffee Finder App에서 Yelp API를 활용해 가까운 카페를 찾는 튜토리얼과 전체 코드를 살펴보는 것도 도움이 될 것 같습니다.
Using Stripe API in React Native with fetch에서는 Stripe API 사용법에 대해 알려주고 있습니다. 위 세 튜토리얼을 통해 서드파티 API 활용 능력을 향상해 보세요.
이전 시리즈로
이전 글을 보고 싶은 분은 아래 링크를 이용하세요.
컨텐츠에 대하여
이 컨텐츠는 저자의 허가 하에 이곳에서 공유합니다.