리액트 네이티브란?
네이티브 애플리케이션:
- 운영체제를 구성하는 언어와 같은 언어로 만들어지는 애플리케이션
- 장점: 높은 성능
- 단점: 개발에 투입되는 리소스가 많아짐
하이브리드 애플리케이션:
- 하이브리드 앱은 모바일 웹 사이트를 감싼 네이트브 앱으로, Apache, Cordova 나 Ionic, Appcelerator Titanium을 이용
- 웹뷰를 이용해 보여지는 영역에 HTML을 보여줌
- HTML/CSS/JS를 이용한 화면 구현
- 네이티브로 만들어진 앱 컨테이너로 네이티브 기능 연동
- 장점: 웹 기술에 익숙하다면 빠른 개발 가능
- 단점: 뷰 퍼포먼스 최적화가 힘듦
과연 리액트 네이티브는 네이티브인가 하이브리드인가?
→ 둘 다 아니다. 아래를 보자
크로스 플랫폼 네이티브 애플리케이션
- 네이티브가 아닌 언어로 작성하지만 빌드 단계에서 네이티브로 변환됨
- 리액트 네이티브, 유니티, 자미란, 플러터 등
- 장점: 자신에게 익숙한 언어로 빠른 개발 가능
- 단점: 네이티브 연동 기능이 많을 경우에는 효율성이 떨어짐
Unity(유니티)
화면 구성(UI): Unity Editor
로직: C#
Xamarin(자마린)
화면 구성: Xamarin.Forms
로직: C#
Flutter
화면 구성 & 로직: Dart
React Native
화면 구성: JSX (XML)
로직: JSX (JS)
JSX란?
- JS + XML
- ECMA Script 6 표준의 자바스크립트 사용
- JSX 내에 스타일시트를 포함함
- 웹의 CSS와 많은 개념을 공유하지만 독자적인 포맷 CSS 파일로 작성 불가
JSX의 예시
<MyButton color="blue" shadowSize={2}>
Click Me
</MyButton>
HTML과 XML과 유사점이 많다.
리액트의 랜더링
JSX → React(Virtual Dom) → HTML(View)
리액트 네이티브의 랜더링
JSX → React Native(Virtual Dom) → Android(View)
→ IOS(View)
어플리케이션의 구조
- 데이터 처리는 자바스크립트가 수행하고 뷰와 자바스크립트 엔진을 연결하는 브릿지가 존재
Expo란?
리액트 학습하는 목적으로 주로 사용
Expo는 CLI보다 접근이 쉬움
import * as React from 'react';
import { SafeAreaView, Text, View, StyleSheet } from 'react-native'; // SafeAreaView 노치 부분을 제외하고 화면을 잡아줌 노치가 없는 경우는 그냥 뷰랑 똑같음
import Constants from 'expo-constants'; // 엑스포는 화면 전체를 사용한다. 스테이터스바 까지도
// 이미지, 텍스트 등 "컨텐츠" 이를 감싸고 있는 것이 "컨테이너"
export default function App() {
// React.Fragment 실제 렌더링에 반영되지 않는 추상 컨테이너
return ( // XML 문법 component마다 쓸수 있는 style이 있음
<SafeAreaView style={styles.container}>
<Text>Text</Text>
</SafeAreaView>
);
}
const styles = StyleSheet.create({ // styleSheet 생성
container: {
flex: 1,
paddingTop: Constants.statusBarHeight,
}
});
// 뷰를 화면 꽉차게 잡아주는 작업을 제일 먼저 함 flex: 1 borderWidth: 1
// flex: 내가 사용할 수 있는 만큼의 크기를 가질거야
리액트 네이티브의 가장 기본 상태
로또 번호 예제
import * as React from 'react';
import { Button, SafeAreaView, Text, View, StyleSheet } from 'react-native'; // SafeAreaView 노치 부분을 제외하고 화면을 잡아줌 노치가 없는 경우는 그냥 뷰랑 똑같음
import Constants from 'expo-constants'; // 엑스포는 화면 전체를 사용한다. 스테이터스바 까지도
import _ from 'lodash';
import styled from 'styled-components/native';
let numbers = [];
// 1부터 45의 숫자 생성
_.times( 45, n => numbers.push( n+1 ));
// 그리고 6개의 숫자 섞음
// numbers = _.shuffle(numbers);
const Row = styled.View`
flex-direction: row;
margin-bottom: 24px;
`;
const Ball = styled.View`
width: 50px;
height: 50px;
border-radius: 25px;
background: ${ props => {
if( props.value < 11){
return '#e5e251';
}
else if( props.value < 21){
return '#517FE5';
}
else if( props.value < 31){
return '#E54036';
}
else if( props.value < 41){
return '#e5e5e5';
}
else{
return '#43BF74'
}
} };
justify-content: center;
align-items: center;
`;
const Label = styled.Text`
font-size: 20px;
color: #000000;
font-weight: bold;
`;
const Container = styled.SafeAreaView`
flex: 1;
justify-content: center;
align-items: center;
padding-top: ${ Constants.statusBarHeight }px
`; // template literals
// 스타일드 컴포넌트 px을 사용해야함
// 이미지, 텍스트 등 "컨텐츠" 이를 감싸고 있는 것이 "컨테이너"
export default function App() {
// 상태 변화 state
const [displayNumbers, setNumbers] = React.useState(_.shuffle(numbers)); // hook
// displayNumbers - 상태의 읽기 전용값
// setNumbers - 상태를 변경하기 위한 업데이트 함수
// React.Fragment 실제 렌더링에 반영되지 않는 추상 컨테이너
return ( // XML 문법 component마다 쓸수 있는 style이 있음
<Container>
<Row>
<Ball value={ displayNumbers[0]}>
<Label> {displayNumbers[0]}</Label>
</Ball>
<Ball value={ displayNumbers[1]}>
<Label>{displayNumbers[1]}</Label>
</Ball>
<Ball value={ displayNumbers[2]}>
<Label>{displayNumbers[2]}</Label>
</Ball>
<Ball value={ displayNumbers[3]}>
<Label>{displayNumbers[3]}</Label>
</Ball>
<Ball value={ displayNumbers[4]}>
<Label >{displayNumbers[4]}</Label>
</Ball>
<Ball value={ displayNumbers[5]}>
<Label >{displayNumbers[5]}</Label>
</Ball>
</Row>
<Button title="다시 뽑기" onPress={()=>setNumbers(_.shuffle( numbers ))}/>
</Container>
);
}
const styles = StyleSheet.create({ // styleSheet 생성
container: {
flex: 1,
paddingTop: Constants.statusBarHeight,
justifyContent: 'center',
alignItems: 'center',
},
row:{
flexDirection: 'row',
margin: 24,
},
ball:{
width: 50,
height: 50,
backgroundColor: "#e5e5e5",
borderRadius: 25,
justifyContent: "center",
alignItems: 'center',
},
text: {
fontSize: 20,
color: '#000000',
fontWeight: 'bold',
}
});
// 뷰를 화면 꽉차게 잡아주는 작업을 제일 먼저 함 flex: 1 borderWidth: 1
// flex: 내가 사용할 수 있는 만큼의 크기를 가질거야
// 리액트 네이티브는 단위를 안쓰고 모든 단위는 px로 고정 되어 있다
// 50, '50%' 중하나
시계 예제
App.js
import * as React from 'react';
import { Text, View, StyleSheet } from 'react-native';
import Constants from 'expo-constants';
import styled from 'styled-components/native';
import Container from './components/Container';
import Row from './components/Row';
import moment from 'moment';
// window, document 참조하는 라이브러리 사용 불가 ex) Jquery
const Label = styled.Text`
font-size: 36px;
font-weight: bold;
`;
export default function App() {
// moment() 현재 시각 생성
const [now, setNow] = React.useState( moment() );
// 유스이펙트가 실행될때
// 1. 이 컴포넌트가 처음으로 표시될 때
// 2. 주시하는 대상이 변화가 일어날 때
React.useEffect( ()=>{
//동작
setInterval( () => {
setNow(moment());
}, 1000) // 1초마다 setNow 실행
}, [/*주시 대상 */] );
return (
<Container>
<Row>
<Text>{now.format('ddd / MMM Do / YYYY')}</Text>
</Row>
<Row>
<Label>{now.format('HH')}</Label>
<Label>{parseInt( now.format('s'), 10) % 2 === 1 ? ':' : ' '}</Label>
<Label>{now.format('mm')}</Label>
<Label>{parseInt( now.format('s'), 10) % 2 === 1 ? ':' : ' '}</Label>
<Label>{now.format('ss')}</Label>
</Row>
</Container>
);
}
./components/Row.js
import styled from 'styled-components/native';
const Row = styled.SafeAreaView`
flex-direction: row;
`;
export default Row;
./components/Container.js
import styled from 'styled-components/native';
const Container = styled.SafeAreaView`
flex: 1;
justify-content: center;
align-items: center;
`;
export default Container;
오늘의 추천 검색어
- react-navigation
- lodash
- flexDirection
- justifyContent: 'flex-end'
- alignItems: 'center'
- MDN arrow function
- 프롭스
- 컴포넌트
- MDN export import
- MDN template literals
- flexbox 공부: flexbox frogyy