React Native 002 - Basics
Core Components
- 리액트 네이티브에 빌드 → 리액트 네이티브에 의해 제공된 네이티브 UI 위젯으로 번역(translation)
Styling
- CSS는 없음
- Inline Styles, StyleSheet Objects (CSS 문법 기반이지만, 속성, 특징의 일부만 지원함)
- StyleSheet Objects를 권장
앱 구상
사소하지만, 그럼에도 불구하고 매우 중요하고 도움되는 앱을 제작해보겠습니다.
목표를 추가하는 버튼 구성, 목표 리스트 화면에 보여지고, 한 목표를 탭하면 삭제할 수 있도록 구현
중요 컴포넌트
- 텍스트를 작성하려면,
<Text>
태그로 텍스트를 꼭 감싸주어야 함. <View>
: 텍스트, 이미지, 유저 인풋에 대한 응답 등에 사용되는 스크린 위의 작은 네모 상자 원소, 기본 빌딩 블락
레이아웃
-
리액티브 RN의 대부분 컴포넌트는 style 속성을 가짐
<View style={{padding: 30}}></View>
-
flex box
-
React Native의 컴포넌트는 기본 속성이 flex로 되어 있어 flex container를 이룹니다. 따라서 flex 관련 속성을 사용할 수 있습니다.
-
main-axis, cross-axis(main-axis와 수직)
-
flexDirection : 'row' (→), 'column' (↓), 'row-reverse' (←), 'column-reverse' (↑)
web 의 flex는 'row'가 기본이지만,
app 에서의 flex는 'column'이 기본입니다.
-
justfiyContent (main-axis기준 정렬), alignItems (cross-axis기준 정렬)
'center', 'stretch', 'space-between', 'space-around' 등
-
flex container 안의 flex item 들에서 사용할 수 있는 속성
- flex: 1 → flex contatiner 의 크기에 따라 flex item의 크기가 결정됨
- 여러 flex item들이 있고, flex: 1, flex: 2 이렇게 있으면 각각 영역을 1/3, 2/3 씩 차지
-
-
<View>
의 기본 크기는 안에있는 텍스트, 이미지 등의 크기에 비례
Inline vs StyleSheet
-
lnline 스타일은 태그안에 스타일 속성을 기록하므로, 복잡한 스타일은 가독성이 좋지 않습니다.
-
StyleSheet 객체를 통해, 객체 형태로 각각의 스타일을 생성할 수 있습니다.
import { StyleSheet } from 'react-native'; export default function App() { return ( <View style={styles.style1}> <View style={styles.style2}> </View> </View> ); } const styles = StyleSheet.create({ style1: { padding: 30 }, style2: { color: white; } })
StyleSheet 객체는 각 스타일 문법의 검증(validation)과 잠재적인 성능 향상을 제공합니다.
상태, 이벤트 관리(State, Event)
-
useState
이용, 상태와 상태 업데이트를 관리import React, { useState } from 'react'; import { StyleSheet, Text, View, TextInput, Button } from 'react-native'; export default function App() { const [enteredGoal, setEnteredGoal] = useState(''); const [courseGoals, setCourseGoals] = useState([]); const goalInputHandler = (enteredText) => { setEnteredGoal(enteredText); }; const addGoalHandler = () => { setCourseGoals(currentGoals => [...currentGoals, enteredGoal]); }; return ( <View style={styles.container}> <Text>Wordbe's App</Text> <View style={styles.innterView}> <TextInput placeholder="Course Goal" style={styles.textInputStyle} onChangeText={goalInputHandler} value={enteredGoal} /> <Button title="Add" onPress={addGoalHandler} /> </View> <View> {courseGoals.map((goal) => <Text key={goal}>{goal}</Text>)} </View> </View> ); }
-
위 예제의 경우, enteredGoal 에 입력된 데이터를 coursGoals 에 추가하며, 이를
map
메소드를 이용해서 출력 -
map
메소드에서Text
태그로 출력할 때, key 입력을 해주면, 효율적으로 리스트를 관리할 수 있습니다.
Styling
<Text>
태그는 style 속성을 많이 지원하지 않으므로,<View>
로 덮어씌운 후 스타일링을 적용하는 것이 좋습니다.- key는 루트 컴포넌트에 적용시켜주어야 합니다.
- RN styling 속성에는 CSS와 다르게
marginVertical
이 있습니다.
<View>
{courseGoals.map((goal) =>
<View key={goal} style={styles.listItem}>
<Text>{goal}</Text>
</View>)}
</View>
ScrollView
-
web 페이지 화면이 꽉차면 자동으로 스크롤이 생기지만, 앱은 설정해주어야 합니다.
import { ScrollView } from 'react-native';
-
화면을 넘는 컴포넌트를 스크롤뷰로 감싸주면 됩니다.
FlatList
ScrollView
의 경우, 보이지 않는 요소가 화면에 없더라도 모두 렌더링 되기 때문에 앱을 느리게 할 수 있습니다.FlatList
는 필요한 것만 렌더링하게 하여 스크롤링을 최적화합니다.
<View>
{courseGoals.map((goal) =>
<View key={goal} style={styles.listItem}>
<Text>{goal}</Text>
</View>)}
</View>
위 코드를 아래와 같이 변경할 수 있습니다.
<FlatList
data={courseGoals}
renderItem={(itemData) => {
return (
<View style={styles.listItem}>
<Text>{itemData.item.value}</Text>
</View>
);
}}
/>
-
단, 데이터는 {key, value} 형식의 자바스크립트 객체여야 합니다.
-
data
: 리스트 형식의 데이터 안에 key, value 값을 가진 객체가 있어야 합니다. -
rennderItem
: { } 안에 함수를 넣으면, data 의 인자를 하나씩 받아 함수에 넣어 반환합니다. -
FlatList는
key
라는 요소를 기본 키로 인식합니다. 이를 커스터마이징 하려면keyExtractor
를 사용합니다.예) key 대신 id 를 사용할 경우
const addGoalHandler = () => { setCourseGoals((currentGoals) => [ ...currentGoals, { id: Math.random().toString(), value: enteredGoal } ]); }; ... <FlatList keyExtractor={(item, index) => item.id} data={courseGoals} renderItem={(itemData) => { return ( <View style={styles.listItem}> <Text>{itemData.item.value}</Text> </View> ); }} />
컴포넌트 분리하기
App.js
에 몰려있던 내용들을 유지/보수 및 가독성을 위해 components/GoalInput.js
, components/GoalItem.js
에 분산시켜 봅시다.
App.js
import React, { useState } from 'react';
import {
StyleSheet,
Text,
View,
TextInput,
Button,
ScrollView,
FlatList
} from 'react-native';
import GoalItem from './components/GoalItem';
import GoalInput from './components/GoalInput';
export default function App() {
const [courseGoals, setCourseGoals] = useState([]);
const addGoalHandler = (goalTitle) => {
setCourseGoals((currentGoals) => [
...currentGoals,
{ id: Math.random().toString(), value: goalTitle }
]);
};
return (
<View style={styles.container}>
<Text>Wordbe's App</Text>
<GoalInput onAddGoal={addGoalHandler} />
<FlatList
keyExtractor={(item, index) => item.id}
data={courseGoals}
renderItem={(itemData) => {
return <GoalItem title={itemData.item.value} />;
}}
/>
</View>
);
}
components/GoalInput.js
import React, { useState } from 'react';
import { View, TextInput, Button, StyleSheet } from 'react-native';
function GoalInput(props) {
const [enteredGoal, setEnteredGoal] = useState('');
const goalInputHandler = (enteredText) => {
setEnteredGoal(enteredText);
};
return (
<View style={styles.innerView}>
<TextInput
placeholder="Course Goal"
style={styles.textInputStyle}
onChangeText={goalInputHandler}
value={enteredGoal}
/>
<Button title="Add" onPress={props.onAddGoal.bind(this, enteredGoal)} />
</View>
);
}
const styles = StyleSheet.create({
textInputStyle: {
marginRight: 5,
borderColor: 'black',
borderWidth: 1
},
innerView: {
flexDirection: 'row',
padding: 30
}
});
export default GoalInput;
- App.js 에서 보면
GoalInput
컴포넌트의 props 로addGoalHandler
함수를 전달해주었습니다. - GoalInput.js 에서는 받아온 함수를 Button의 인자로 사용하고 있습니다.
addGoalHandler
함수는 props.onAddGoal로 받아와지는데, 이 함수는 이전 객체 currentGoals와 enteredGoal이라는 인수가 필요합니다. - 이 때, bind 함수에 this 인자를 넣어서 업데이트 사항이 반영된 객체가 계속 올 수 있도록 반영합니다.
components/GoalItem.js
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
function GoalItem(props) {
return (
<View style={styles.listItem}>
<Text>{props.title}</Text>
</View>
);
}
const styles = StyleSheet.create({
listItem: {
pading: 10,
marginVertical: 3,
backgroundColor: '#ccc',
borderColor: 'black',
borderWidth: 1
}
});
export default GoalItem;
'App > React Native' 카테고리의 다른 글
[React Native] Expo 없이 앱 build하기 (325) | 2020.06.11 |
---|---|
[React Native] 5 React Navigation 설정 (393) | 2020.05.16 |
[React Native] 4 반응형, 적응형 사용자 인터페이스 만들기 (281) | 2020.05.10 |
[React Native] 3 Touchable, Modal Overlay (269) | 2020.05.07 |
[React Native] 1 React Native 시작, Expo (256) | 2020.05.05 |
댓글