① stateful : 상태를 유지한다.
class HelloWorld extends React.Component{
constructor(){
super()
this.state = {name: 'Christ'}
}
render(){
return(
<SomeComponent />
)
}
}
② stateless: 상태를 유지하지 않는다.
const HelloWorld = () => (
<SomeComponent />
)
JSX
스레드 처리
: 네이티브 기기와 통신하는 모든 자바스크립트의 기능은 분리된 별도의 스레드로 처리된다.
때문에 사용자는 모든 자바스크립트의 동작은 네이티브 플랫폼과의 인터랙션에서 별도의 스레드로 처리됩니다.
이로 인하여 사용자 인터페이스와 애니메이션 구동이 별도의 간섭없이 자연스럽게 보이게 된다.
리액트
: 리액트 네이티브의 가장 큰 특징은 리액트를 사용한다는 것이다.
단방향 데이터 흐름
: 양방향 데이터 흐름에 비하여 단순하므로 리액트 네이티브로 작성된 모든 애플리케이션에 사용된다.
-> 애플리케이션에 대한 데이터가 흩어진 형태가 아닌 데이터의 계층 구조가 하나의 방식이다.
즉, 리액트는 최상위 컴포넌트에서 아래 모든 방향으로 단방향 데이터 흐름이 만들어진다.
디핑(코드 비교)
: 리액트는 코드를 비교하고, 이를 네이티브 컴포넌트에 반영한다.
이 방식은 UI와 네이티브 컴포넌트를 갱신하는 스레드에 최소한의 데이터를 전달할 때 사용한다.
컴포넌트로 생각하기
: 리액트 네이티브에서 UI를 만들 때는 여러 컴포넌트를 조립해 앱을 만든다고 생각하면 편하다.
개발자 가용성
개발자 생산성 (하나의 팀이 안드로이드와 ios를 전부 개발할 수 있다)
성능: 모바일 앱에 크게 뒤쳐지지 않는다
단방향 데이터 흐름 (앱이 이해하기 쉬워진다)
개발자 경험
트랜스 파일링: 트랜스파일러가 특정 프로그램 언어로 작성된 소스코드를 받아서 다른 프로그램 언어로 코드를 변환해 주는 것
(리액트 네이티브는 기본적으로 내장된 바벨을 사용한다.)
생산성과 효율성
커뮤니티
오픈 소스 ( 페이스북 팀 말고도 수백 명의 개발자가 리액트 네이티브에 기여하고 있다.)
빈번한 업데이트
크로스 클랫폼 모바일 앱을 만드는 대안
코르도바 / 자마린 / 플러터 등
네이티브 iOS와 안드로이드, 코르도바 같은 플랫폼과 비교해 아직 덜 성숙 되었다.
개발자가 리액트를 다루어 보지 않았다면 완전히 새로운 기술을 습득해야 한다.
리액트 네이티브에서는 컴포넌트 개념이 중요하다. 컴포넌트는 데이터와 UI 요소의 집합체로 이를 통해 화면이 구성되고 결국 앱이 만들어진다.
내장 컴포넌트가 있지만 프레임워크를 사용해 직접 컴포넌트를 만들 수도 있다.
컴포넌트 유형 | HTML | 리액트 네이티브 JSX |
---|---|---|
Text | <span></span> | <Text></Text> |
View | <div><span></span></div> | <View><Text></Text></View> |
Touchable highlight | <button><span></span></button> | <TouchableHighlight><Text></Text></TouchableHighlight> |
리액트 네이티브는 View와 Text, Image 등과 같은 네이티브 컴포넌트를 기본적으로 제공합니다.
개발자는 마치 조립 블록처럼 이들 네이티브 컴포넌트를 사용해 새로운 컴포넌트를 만들 수 있습니다.
<Button 컴포넌트 만들기>
import {Text, TouchableHighlight} from 'react-native'
const Button = () => {
<TouchableHighlight>
<Text>
Hello World
</Text>
</TouchableHighlight>
}
<Button 컴포넌트를 가져와 사용하기>
import React from 'react'
import {Text, TouchableHighlight} from 'react-native'
import Button from './components/Button'
const Home = () => {
<View>
<Text>Welcome to the Hello World Button!</Text>
<Button />
</View>
}
컴포넌트를 만드는 방식 몇 가지
1. createClass 구문 (ES5, JSX)
const React = require('react')
const ReactNative = require('react-native')
const {View, Text} = ReactNative
const MyComponent = React.createClass({
render(){
return(
<View>
<Text> Hello World </Text>
</View>
)
}
})
2. class 구문 (ES2015, JSX)
컴포넌트가 고유한 상태를 유지하는 컴포넌트 (stateful 컴포넌트) 때에는 ES2015 클래스 사용이 일반적이다.
이 방식은 리액트 네이티브 커뮤니티나 리액트 네이티브 개발자들이 추천하고 있다.
import React from 'react'
import {View, Text} from 'react-native'
class MyComponent extends React.Component{
render(){
return(
<View>
<Text>Hello World!</Text>
</View>
)
}
}
3. stateless ((재사용) 컴포넌트(JSX))
import React from 'react'
import {View, Text} from 'react-native'
const MyComponent = () => {
<View>
<Text>Hello World!</Text>
</View>
}
/*
function MyComponent (){
return <View><Text>Hello From Stateless</Text></View>
}
*/
4. createElement (자바스크립트)
React.createElement는 사용하는 경우가 드물다. 아마 이 구문을 사용해 리액트 네이티브 요소를 만드는 일은 없을 것이다.
React.createElement(type, props, children)
import React from 'react'
import {View, Text} from 'react-native'
class MyComponent extends React.Component{
render(){
return(
React.createElement(View, {},
React.createElement(Text, {}, "Hello")
)
)
}
}
/* 다음과 동일하다
import React from 'react'
import {View, Text} from 'react-native'
class MyComponent extends React.Component{
render(){
return(
<View>
<Text>Hello</Text>
</View>
)
}
}
*/
import
컴포넌트 선언
class Home extends Component { }
여기서는 리액트 네이티브 Component 클래스를 확장하고 Home이라는 이름으로 인스턴스를 새로 생성하였습니다. 앞에서는 React.Component와 같이 선언했지만, 코드에서는 Component로만 선언하고 있습니다.
이는 객체 구조 분해 할당(비구조화) 를 이용해 처리된 것입니다.
이런 방식을 이용하면 React.Component를 줄여서 Component만으로 사용할 수 있습니다.
render 메서드
render 메서드를 호출하는 경우 반드시 하나의 자식요소를 반환합니다.
rener 함수 밖에 선언된 변수나 함수들은 이 위치에서 실행할 수 있습니다.
연산이 필요하다면 state나 props를 사용해 변수를 선언하거나 컴포넌트의 state를 조작하지 못하는 함수를 실행하면 되는데 render 메서드와 return 구문 사이에서 처리할 수 있습니다.
Exports
...
export default Home
<ES5>
module.exports = 'Home'
import React from 'react'
import {View, Text} from 'react-native'
class Home extends React.Component{
const Header = () => {
<View>
<Text> Header </Text>
</View>
}
const Footer = () => {
<View>
<Text> Footer </Text>
</View>
}
const Main = () => {
<View>
<Text> Main </Text>
</View>
}
render(){
return(
<View>
<Header />
<Main />
<Footer />
</View>
)
}
}
npm install -g create-react-native-app
//npx 사용을 권고한다( 필요한 모듈들을 자동설치하기 때문)
npx create-react-native-app myProject
npm install -g react-native-cli
//npx를 이용해 설치한 경우 자동으로 전역 라이브러리들을 설치하므로 필요하지 않다.
npx react-native init myProject
<설치 과정에서 만들어진 파일들과 폴더들이 무엇인지 알아보자>
android: 이 폴더에는 안드로이드 플랫폼용 코드와 의존성 라잉브러리들이 있다.
ios: 이 폴더에는 iOS플랫폼용 코드와 의존성 라이브러리들이 있다.
node_modules: 리액트 네이티브는 npm(node package manager) 모듈을 사용해 의존성 라이브러리들을 관리한다.
.package.json파일이 의존성 라이브러리들을 식별하고 버전을 관리한다.
.flowconfig: 페이스북이 오픈 소스로 만든 Flow는 자바스크립트용 타입 검사기이다. (Flow는 Typescript와 같은 종류로 이 파일에는 Flow에 대한 경 설정이 되어 있다 (사용할 경우))
.gitignore: 버전 관리가 필요하지 않은 파일의 경로를 저장하는 파일
.watchmanconfig : 페이스북이 오픈소스로 만든 Watchman은 리액트 네이티브에서 사용하는 파일 감시 도구
index.js: 앱을 실행하면 먼저 이 파일에서 시작합니다. 이 파일에서는 App.js를 가져오고 AppRegistry.registerComponent를 호출하고 최종적으로 앱이 시작된다.
App.js: index.js를 포함하고 있는 프로젝트에서 사용하는 메인이 되는 파일입니다.
index.js파일의 import 구문을 변경해서 다른 파일을 사용하게 할 수 있다.
package.json: npm 모듈의 환경설정이 들어 있다. npm으로 파일을 설치하면 종속 요소들이 여기에 기록된다.
import { StatusBar } from 'expo-status-bar';
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
export default function App() {
return (
<View style={styles.container}>
<Text>Open up App.js to start working on your app!</Text>
<StatusBar style="auto" />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
StyleSheet는 CSS를 추상화된 방식으로 작성하게 한다.
리액트 네이티브에서는 인라인으로나 스타일시트를 사용해서 스타일을 선언할 수있다.
<View style={styles.container}>
이 코드는 다음 코드에 해당된다.
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
AppRegistry.registerComponent('firstInstall',() => App);
//혹은 이거
registerRootComponent(App);
이것은 모든 리액트 네이티브 앱에서 자바스크립트 진입점(entry point)입니다.
index.js 파일에서 개발자가 이 함수를 호출할 수 있는 유일한 지점으로, 앱의 루트 컴포넌트는 자체적으로 AppRegistry.registerComponent( )를 이용해서 등록해야 한다.
그럼 네이티브 시스템은 앱 번들을 로드할 수 있으며, 다 되었다면 앱을 실행할 수도 있다.
[참고]
readme.md파일에 기본적인 expo 사용법을 기록해 두었다!