이전에 이어서 AwesomeProject를 확장하도록 하겠습니다. 이번의 예제는 React Native Tutorial에 나오는 코드를 사용하고 확장할 것입니다.
작업 환경을 설정합시다.
더미 데이터와 간단한 코드로 시작합시다. 편의를 위해 여기의 코드는 안드로이드에서 테스트하는 것으로 가정하겠습니다. 둘의 가장 큰 차이는 사용하는 파일입니다. 안드로이드에서는 index.android.js
를 사용하고 iOS에서는 index.ios.js
파일을 사용합니다.
만약 아이폰을 사용하면 index.ios.js
을 수정하고 안드로이드를 사용한다면 index.android.js
를 수정합니다. 둘다 사용한다면 둘 다 수정해보세요.
안드로이드 환경설정
코드를 최초 실행할 때는 아래와 같이 입력합시다.
react-native run-android
수행이 완료되면 Genymotion을 켜두었으면 Genymotion에서, 실 단말을 연결해두었다면 실 단말로 앱이 수행되게 됩니다.
만약 안드로이드 5.0 이상의 단말에서 화면이 제대로 나오지 않을 수 있습니다. 그런 경우 아래의 커맨드를 이용합시다.
adb reverse tcp:8081 tcp:8081
다시 앱을 실행해보면 정상적으로 표시되는 것을 알 수 있습니다.
iOS의 환경설정
iOS에서는 아래의 커맨드로 수행할 수 있습니다.
open AwesomeProject/ios/AwesomeProject.xcodeproj
혹은 다음의 방법도 있습니다.
react-native run-ios
첫번째 수정
index.android.js
파일을 열어 간단한 내용을 수정해봅시다. React Native!
라는 문구를 React Native?
로 바꾸겠습니다.
class AwesomeProject extends Component {
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>
Welcome to React Native?
</Text>
<Text style={styles.instructions}>
To get started, edit index.android.js
</Text>
<Text style={styles.instructions}>
Shake or press menu button for dev menu
</Text>
</View>
);
}
}
수정된 내용을 보기 위해 (안드로이드)
수정된 내용은 앱에 바로 표시가 되지 않습니다. 화면을 갱신하기 위해 폰을 흔들어 봅시다. 메뉴 키가 있는 폰에서는 메뉴키를 눌러도 됩니다.
제일 위에 있는 Reload JS
를 누르면 화면이 업데이트 됩니다.
하지만 이렇게 항상 수동으로 갱신하는 일은 귀찮은 일입니다. 다시 화면을 흔들어서 Enable Live Reload
를 누릅시다. 이 기능을 활성화 시키면 우리가 수정한 내용으로 항상 업데이트가 이루어집니다.
수정된 내용을 보기 위해 (iOS)
iOS에서는 커맨드 + R을 입력해서 화면을 리프레쉬하는 것을 추천합니다.
목업 데이터 추가하기
상단의 import
구문에 Image
를 추가합니다.
import React, {
AppRegistry,
Component,
Image,
StyleSheet,
Text,
View
} from 'react-native';
다음으로 MOCKED_MOVIES_DATA
를 추가합시다. 개발 단계를 위해 마련한 목업 데이터입니다.
var MOCKED_MOVIES_DATA = [
{title: 'Title', year: '2015', posters: {thumbnail: 'http://i.imgur.com/UePbdph.jpg'}},
];
이제 AwesomeProject
클래스의 render
메서드를 수정합니다.
render() {
var movie = MOCKED_MOVIES_DATA[0];
return (
<View style={styles.container}>
<Text>{movie.title}</Text>
<Text>{movie.year}</Text>
<Image source={{uri: movie.posters.thumbnail}} />
</View>
);
AwesomeProject
클래스의 전체 모습은 아래와 같습니다.
class AwesomeProject extends Component {
render() {
var movie = MOCKED_MOVIES_DATA[0];
return (
<View style={styles.container}>
<Text>{movie.title}</Text>
<Text>{movie.year}</Text>
<Image source={{uri: movie.posters.thumbnail}} />
</View>
);
}
}
이후 앱을 확인하면 Title 2015를 볼 수 있습니다.
하지만 이미지는 제대로 표시되지 않습니다. 이미지를 제대로 표시하려면 Image
의 크기가 설정되지 않아서입니다. 스타일쉬트 styles
를 수정합시다.
var styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
thumbnail: {
width: 53,
height: 81,
},
});
StyleSheet.create
메서드를 이용해서 스타일쉬트 styles
를 만들었고 이 안에 container
와 thumbnail
두개의 항목이 있습니다.
flex: 1
로 설정되었기 때문에 container
의 사이즈는 유연하게 결정되며 주변 여백에 따라 그것을 채우도록 설정되어 있습니다.
flex
를 포함하여 여러 내용을 알기 위해서는 플렉스박스(Flexbox) 모델을 참고해야하는데 여기에서는 간단히 설명하겠습니다. justifyContent
는 메인 축 alignItems
는 크로스 축을 기준으로 어떻게 정렬할지를 결정합니다. backgroundColor
는 배경색상입니다. width
와 height
는 각기 가로와 세로폭입니다.
스타일쉬트를 수정하였으면 styles
의 thumbnail
항목, 즉 styles.thumbnail
을 Image
에서 쓰도록 설정합시다.
<Image
source={{uri: movie.posters.thumbnail}}
style={styles.thumbnail} />
제대로 설정했다면 AwesomeProject
는 아래와 같은 모양이 됩니다.
class AwesomeProject extends Component {
render() {
var movie = MOCKED_MOVIES_DATA[0];
return (
<View style={styles.container}>
<Text>{movie.title}</Text>
<Text>{movie.year}</Text>
<Image
source={{uri: movie.posters.thumbnail}}
style={styles.thumbnail} />
</View>
);
}
}
이제 리로딩된 결과를 확인해봅시다.
스타일 수정하기
이제 스타일링을 조금 고쳐봅시다. 먼저 가로 방향으로 배치하기 위해 container
에 flexDirection
을 row
로 지정하겠습니다. 이는 나열되는 항목들을 가로로 배치하겠다는 의미입니다.
container: {
flex: 1,
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
만약에 세로로 표현하겠다면 flexDirection
의 값을 column
으로 지정합니다. 기본 값이 column
이기 때문에 별도로 지정할 필요는 없습니다.
View
항목을 아래와 같이 수정합시다. Image
를 앞으로 배치하고 두개의 Text
는 새로운 View
로 감싸도록 합시다.
<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>
두개의 Text
를 View
로 감싸고 별도의 스타일 styles.rightContainer
를 지정한 걸 볼 수 있습니다. 이렇게 감싸둔 것은 계층적으로 레이아웃을 구성하기 위함입니다. 상위 요소 styles.container
에서 row
방향으로 flexDirection
을 지정하여 가로 방향으로 레이아웃이 구성되지만 새로운 View
에서 지정한 styles.rightContainer
에서는 자식들을 세로 방향으로 레이아웃할 수 있습니다.
오른쪽 컨테이너 도입
styles.rightContainer
을 위한 스타일쉬트도 구성해봅시다.
rightContainer: {
flex: 1,
},
스타일쉬트를 바꾸면 다음과 같이 보입니다.
왼편으로 많이 쏠려 있습니다. 타이틀과 연도를 담은 Text
를 중앙으로 정렬합시다.
title: {
fontSize: 20,
marginBottom: 8,
textAlign: 'center',
},
year: {
textAlign: 'center',
},
데이타 가져오기
실제 데이터를 가져오기 위해 변수 REQUEST_URL
를 정의합니다.
var REQUEST_URL =
'https://raw.githubusercontent.com/facebook/react-native/master/docs/MoviesExample.json';
AwesomeProject
클래스 내에 생성자를 만듭시다.
constructor(props) {
super(props);
this.state = {
movies: null,
};
}
this.state
를 통해 movies
를 null
로 초기화합니다.
아래의 메서드들도 클래스 내에 추가합니다.
componentDidMount() {
this.fetchData();
}
컴포넌트가 마운트되면 (componentDidMount
) fetchData
를 수행합니다. AwesomeProject
가 연결되어 화면에 표시될 때 데이터 로딩을 요청하는 것입니다.
fetchData() {
fetch(REQUEST_URL)
.then((response) => response.json())
.then((responseData) => {
this.setState({
movies: responseData.movies,
});
})
.done();
}
실제 데이터를 가져오는 메서드 fetchData
입니다. 이전에 정의한 REQUEST_URL
URL을 이용해서 데이터를 가져옵니다.
fetch가 끝나면 .then
으로 연결된 프로미스(promise) 체인이 수행됩니다. .done
은 그 프로미스 체인이 끝났다는 것을 의미합니다. 데이터를 가져오면 먼저 response.json()
를 통해 json 데이터를 파싱하고 그 결과를 this.setState
를 통해 컴퍼넌트의 상태를 설정합니다.
리액트 네이티브는 this.setState
가 상태를 바꿀 때 마다 렌더링을 새로 합니다. 그렇기 때문에 fetch
가 수행이되고 json 파싱을 거쳐 상태 설정이 완료되면 다시 그려지게 되는 것입니다.
render
를 아래와 같이 수정합시다.
render() {
if (!this.state.movies) {
return this.renderLoadingView();
}
var movie = this.state.movies[0];
return this.renderMovie(movie);
}
데이터가 없는 경우 (아직 fetchData
가 끝나지 않은 경우) renderLoadingView
가 호출되며 데이터를 가져오면 첫번째 데이터(this.state.movies[0]
)만 renderMovie
의 인자로 전달하여 화면에 표시합니다.
데이터가 없을 때 표시되는 renderLoadingView
는 아래와 같습니다.
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>
);
}
데이터가 있는 경우 파라미터 movie
로 전달 받아 출력합니다.
제대로 수행이 되면 아래와 같이 항목 하나의 정보를 네트워크에서 받아 표시합니다.
리스트 뷰
여러개의 항목을 출력하기 위해서는 리스트 뷰를 이용합니다. 먼저 ListView
를 import
합니다.
import React, {
AppRegistry,
Component,
Image,
ListView,
StyleSheet,
Text,
View
} from 'react-native';
이제 render
메서드가 ListView
를 쓰도록 수정합니다.
render() {
if (!this.state.loaded) {
return this.renderLoadingView();
}
return (
<ListView
dataSource={this.state.dataSource}
renderRow={this.renderMovie}
style={styles.listView}
/>
);
}
개별 라인은 renderRow
에 지정한 this.renderMovie
메서드에 의해 처리됩니다. 이제 this.state.loaded
에 의해 로딩 중인지를 판단합니다.
dataSource
에 this.state.dataSource
를 사용합니다. 해당 상태를 초기화하고 갱신하는 코드가 필요합니다. 생성자에 초기화하는 코드를 먼저 추가합시다.
constructor(props) {
super(props);
this.state = {
dataSource: new ListView.DataSource({
rowHasChanged: (row1, row2) => row1 !== row2,
}),
loaded: false,
};
}
fetchData
메서드도 해당 상태를 갱신하도록 수정합니다.
fetchData() {
fetch(REQUEST_URL)
.then((response) => response.json())
.then((responseData) => {
this.setState({
dataSource: this.state.dataSource.cloneWithRows(responseData.movies),
loaded: true,
});
})
.done();
}
json 데이터를 이용해 this.state.dataSource
를 업데이트합니다.
마지막으로 스타일쉬트를 업데이트합시다.
listView: {
paddingTop: 20,
backgroundColor: '#F5FCFF',
},
코드를 다 수정하면 다음과 같은 화면이 뜹니다.
함께 쓰면 좋은 제품과 오픈소스 프로젝트
Realm 모바일 데이터베이스는 리액트 네이티브에서 사용할 수 있는 빠르고 간편한 객체형 데이터베이스입니다. 안드로이드와 iOS에서는 이미 널리 사용되고 있으며, 언제나 살아있는 객체로 최신의 데이터를 유지하면서 앱 모델 레이어를 정말 빠르게 작성하도록 도와줍니다. 리액트 네이티브 문서에서 단계별로 따라하면서 적용할 수 있습니다.
Realm 모바일 플랫폼은 더 나은 리액티브 앱 개발을 위해 백엔드 솔루션을 제공합니다. 특별히 관리하지 않아도 데이터가 실시간 동기화되므로 네트워크 연동을 위한 별도의 코딩을 하지 않아도 됩니다. 현재는 안드로이드와 iOS만을 지원하지만, 곧 리액트 네이티브를 지원한다고 하니 Realm 모바일 데이터베이스와 함께 연동하시면 시너지를 누릴 수 있을 겁니다.
React native navbar는 리액트 네이티브에서 편하게 네비게이션 바를 변경할 수 있도록 돕는 라이브러리입니다. 사용자 인터페이스를 개선하고 싶은 분들께 추천합니다.
모바일 앱에서는 사이드 메뉴도 자주 사용되는데요. React native side menu에서 간단하게 사이드메뉴를 만들어주는 라이브러리를 다운받을 수 있습니다.
더 많은 리액트 네이티브 라이브러리가 필요하다면 React.parts를 방문해 보세요.
다음으로
지금까지 네트워크와 리스트를 다루어 보았습니다. 다음 시간에는 Realm을 결합하여 데이터를 저장하고 불러와 보겠습니다. 아래 링크에서 보실 수 있습니다.
이전 글을 보고 싶은 분은 아래 링크를 이용하세요.
컨텐츠에 대하여
이 컨텐츠는 저자의 허가 하에 이곳에서 공유합니다.