React Native Basics2
iOS & Android 스타일링의 차이점
-React Native는 Text 컴포넌트를 해당하는 네이티브 위젯 즉 네이티브 UI요소로 전환하는데 Android에서는 전환된 후 둥근 모서리로 나타나지만 iOS에서는 기본 네이티브 텍스트 출력 요소가 둥근 모서리를 지원하지 않음 => View로 감싸 문제를 해결할 수 있음(좀 더 포괄적인 컨테이너 요소에서 해당하는 기본 요소로 전환되는 것임)
- 웹 CSS와 달리 스타일은 연속적으로 적용되지 않는다.(View 하위에 있는 Text까지 스타일이 적용되지 않음)
ScrollView를 통해 콘텐츠를 스크롤 할 수 있도록 만들기
- React Native에서 제공
- 스크롤 가능한 영역은 부모 요소가 결정하기 때문에 View를 추가해서 사용 가능한 높이를 제한하고 View가 차지할 높이를 설정하는 style을 적용해야 한다.
- 사용가능한 높이를 넘으면 활성됨
- 콘텐츠에 스트롤을 추가할 때 유용하지만 목록이 아주 길어질 경우엔 적합한 솔루션은 아님
- ScrollView는 전체 UI가 렌더링될 때마다 안에 있는 항목을 전부 렌더링한다. 보이지 않더라도 화면 뒤에서 계속 렌더링 됨
- 아이템 목록이 길지 않고 명확히 정의된 UI는 작은 기기 화면에서 보기 힘들 수 있으므로 FlatList가 아닌 Scrollview를 사용
FlatList를 통해 리스트 최적화
- 보이는 항목만 렌더링하고 화면 밖의 항목은 사용자가 스크롤해야 로딩 & 렌더링 됨
- 해당 작업을 FlatList로 전달해서 필요한 사항만 렌더링하는 방식으로 변경
data
prop : 목록에서 출력할 데이터를 지정하는 역할renderItem
prop : 개별 데이터 항목을 렌더링하는 방법을 FlatList에 지시하는 함수를 값으로 가짐 => 내부적으로 객체 생성, index프로퍼티 접근 권한도 제공함
View와 Text를 사용하여 스타일링된 항목을 반환한다.item
prop : renderItem 함수 내에서 사용되는 인자로, 현재 렌더링 중인 데이터 항목을 나타낸다.keyExtractor
: FlatList컴포넌트에 새 프로퍼티를 추가할 수 있음. 함수를 값을 취함.
리스트 항목에 고유한 키를 부여하는 방법을 정의한다. 여기서는 각 목표의 id가 키로 사용됨. React Native에서 리스트 항목을 효율적으로 업데이트하기 위해 고유한 키가 필요하다.
Splitting Components
- 데이터 입력과 관련된 컴포넌트
- goal 한 개를 출력하기 위한 코드와 관련 기능
- 스타일을 코드에 가깝게 유지하는 것이 좋은 습관임
Code
//app/(tabs)/index.tsx
import React, { useState } from 'react';
import {
StyleSheet,
View,
Button,
TextInput,
FlatList,
ListRenderItemInfo,
} from 'react-native';
import GoalItem from '../../components/GoalItem';
interface Goal {
text: string;
id: string;
}
export default function App() {
const [enteredGoalText, setEnteredGoalText] = useState<string>('');
const [courseGoals, setCourseGoals] = useState<Goal[]>([]);
function goalInputHandler(enteredText: string) {
setEnteredGoalText(enteredText);
}
function addGoalHandler() {
setCourseGoals((currentCourseGoals) => [
...currentCourseGoals,
{ text: enteredGoalText, id: Math.random().toString() },
]);
}
return (
<View style={styles.appContainer}>
<View style={styles.inputContainer}>
<TextInput
style={styles.textInput}
placeholder="Your course goal!"
onChangeText={goalInputHandler}
/>
<Button title="Add Goal" onPress={addGoalHandler} />
</View>
<View style={styles.goalsContainer}>
<FlatList
data={courseGoals}
renderItem={(itemData: ListRenderItemInfo<Goal>) => {
return <GoalItem text={itemData.item.text} />;
}}
keyExtractor={(item) => {
return item.id;
}}
alwaysBounceVertical={false}
/>
</View>
</View>
);
}
const styles = StyleSheet.create({
appContainer: {
flex: 1,
paddingTop: 50,
paddingHorizontal: 16,
},
inputContainer: {
flex: 1,
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: 24,
borderBottomWidth: 1,
borderBottomColor: '#cccccc',
},
textInput: {
borderWidth: 1,
borderColor: '#cccccc',
width: '70%',
marginRight: 8,
padding: 8,
},
goalsContainer: {
flex: 5,
}
});
//components/GoalItem.tsx
import React from 'react';
import { StyleSheet, View, Text } from 'react-native';
interface GoalItemProps {
text: string;
}
function GoalItem(props: GoalItemProps) {
return (
<View style={styles.goalItem}>
<Text style={styles.goalText}>{props.text}</Text>
</View>
);
}
export default GoalItem;
const styles = StyleSheet.create({
goalItem: {
margin: 8,
padding: 8,
borderRadius: 6,
backgroundColor: '#5e0acc',
},
goalText: {
color: 'white',
},
});