React에서는 화면 밖을 넘어가면 스크롤을 자동으로 생성해서 스크롤을 할 수 있게 한다.
하지만 불편한 React-Native에는 그딴 건 없다.
react-native에서 ScrollView 컴포넌트를 임포트 해서 스크롤을 만들 수 있다.
<ScrollView style={styles.goalsContainer}>
{courseGoals.map((goal, idx) => (
<View style={styles.goalItem} key={idx}>
<Text style={styles.goalText} key={goal}>
{goal}
</Text>
</View>
))}
</ScrollView>
하지만 이렇게 그냥 ScrollView를 사용해 버리면 내가 원하는 크기로 만들 수 없다.
ScrollView는 부모의 컴포넌트에 따라 높이가 정해진다.
따라서 그냥 ScrollView를 써버리면 그 부모 컴포넌트의 넓이, 길이에 따라서 변하게 되어 내가 원하는 모습의 앱을 구현할 수 없다.
이를 해결하기 위해서는 ScrollView를 View로 감싸준다.
<View style={styles.goalsContainer}>
<ScrollView>
{courseGoals.map((goal, idx) => (
<View style={styles.goalItem} key={idx}>
<Text style={styles.goalText} key={goal}>
{goal}
</Text>
</View>
))}
</ScrollView>
</View>
그리고 ScrollView에 줬던 스타일을 ScrollView를 감싸고 있던 View컴포넌트에 적용하면 원하는 모습의 앱을 구현 할 수 있다.
ScrollView의 경우 끝이 있는 경우에 사용하는 것이 좋다.
ScrollView는 컴포넌트가 10개이든 100개이든 모두 렌더링을 해주고 화면에만 표시가 되지 않기 때문에 성능 저하의 원인 된다.
따라서 무한히 길어지는 끝이 없는 경우에는 ScrollView를 사용할 이유가 없다.
FlatList는 화면에 표시될 항목들만 렌더링 해준다.
그렇기 때문에 ScrollView의 성능저하 문제를 해결할 수 있다.
기존 ScrollView
<View style={styles.goalsContainer}>
<ScrollView>
{courseGoals.map((goal, idx) => (
<View style={styles.goalItem} key={idx}>
<Text style={styles.goalText} key={goal}>
{goal}
</Text>
</View>
))}
</ScrollView>
</View>
FlatList 사용
<FlatList
data={courseGoals}
renderItem={(itemData) => {
return (
<View style={styles.goalItem}>
<Text style={styles.goalText}>{itemData.item}</Text>
</View>
);
}}
/>
기존의 ScrollView를 FlatList로 변경해주면 된다.
이때 주의 해야할 점은 프로퍼티와 렌더링 방식이 변하게 된다.
우선 FlatList는 셀프클로징한다.
또한 직접 map을 이용해서 반복을 하지 않고
data
프로퍼티와 renderItem
프로퍼티를 이용한다.
data
프로퍼티에는 반복을 돌릴 즉 ScrollView에서 map으로 반복시킨 state를 넣어주고
renderItem
프로퍼티에는 결과값을 넣어주면 된다.
방법1
state에 생성할 때 key값을 가진 객체로 만들어서 주는 방법
function addGoalHandler(){
setCourseGoals((currentCourseGoals) => [
...currentCourseGoals,
{text: enteredGoalText, key: Math.random().toString()}
]);
}
<FlatList
data={courseGoals}
renderItem={(itemData) => {
return (
<View style={styles.goalItem}>
<Text style={styles.goalText}>{itemData.item.text}</Text>
</View>
);
}}
/>
위와 같이 만들어주는데 이때 FlatList는 자동으로 key값을 찾게 되며 렌더링 부분을 itemData.item
에서 itemData.item.text
로 변경만 해주면 된다.
방법2
방법1처럼 직접 state를 변경하거나 하면 상관이 없지만 api를 호출하거나 데이터를 수정할 수 없을 경우 key 프로퍼티가 없으면 굉장히 난감하다.
따라서 이러한 경우 keyExtractor 프로퍼티를 이용해서 만들어 준다.
function addGoalHandler() {
setCourseGoals((currentCourseGoals) => [
...currentCourseGoals,
{ text: enteredGoalText, id: Math.random().toString() },
]);
}
// 위와 같이 데이터에 key속성이 없다면??
<FlatList
data={courseGoals}
renderItem={(itemData) => {
return (
<View style={styles.goalItem}>
<Text style={styles.goalText}>{itemData.item.text}</Text>
</View>
);
}}
keyExtractor={(item, idx) => {
return item.id;
}}
/>
keyExtrator를 이용하는데 renderItem과 마찬가지로 함수를 받고 데이터에서 유니크한 값을 받아서 return을 해주면 그 값이 key값이 되는 것이다.