Today I Learned
- React Native 심화 강의 수강
LinearGradient 사용하기
<LinearGradient colors={["transparent", "black"]} style={StyleSheet.absoluteFill} />
배경 이미지에 그라디언트 효과를 줄 때 LinearGradient를 사용한다. colors라는 porp을 넘겨서 배열 형태로 원하는 그라디언트 효과를 구현할 수 있다. ["transparent", "black"]는 투명에서 검은색으로 그라디언트 효과를 주고 싶다는 것을 의미한다.
flex-end 속성
- flex-end: 아이템들을 끝으로 정렬한다. flex-direction이 row(가로 배치)일 때는 아래, column(세로 배치)일 때는 오른쪽에 위치한다.
- 출처 https://studiomeal.com/archives/197
StyleSheet.absoluteFill
// 동일한 코드
<View style={{position: 'absolute', left: 0, right: 0, top: 0, bottom: 0}}>
<View style={StyleSheet.absoluteFill}>
배경이미지 적용 시 자주 사용되는 패턴 코드 간소화
기기의 실제 너비와 높이 구하기
import { Dimensions } from "react-native";
export const { width: SCREEN_WIDTH, height: SCREEN_HEIGHT } =
Dimensions.get("window");
Dimensions API를 통해서 실제 스크린너비와 높이값을 구할 수 있다.
height: ${SCREEN_HEIGHT / 3 + "px"};
사용 예시
react-native-swiper 사용하기
<Swiper height="100%" showsPagination={false} sutoplay loop>
<BestMovieContainer>
...생략...
</BestMovieContainer>
</Swiper>
사용하고자 하는 요소를 <Swiper>로 감싸고 속성을 설정한다. height는 기본적으로 화면 모두를 차지(flex: 1)하기 때문에 필수로 설정해줘야 한다.
참고 https://github.com/leecade/react-native-swiper
로딩 중 화면 표시하기
const [isLoading, setIsLoading] = useState(true);
useState로 isLoading을 만들어서 데이터를 가져오는데 성공하면 setIsLoading(false)로 변경한다.
if (isLoading) {
return (
<Loader>
<ActivityIndicator size="large"/>
</Loader>
);
};
if문으로 isLoading이 true일 때 로딩 애니메이션 표현하는 <ActivityIndicator> 컴포넌트를 이용해서 화면에 띄워준다.
영화정보 API 가져오기
const getNowPlaying = async() => {
const { results } = await fetch(
`${BASE_URL}/now_playing?api_key=${API_KEY}&language=en-US&page=1`
).then((res) => res.json());
setNowPlaying(results)
setIsLoading(false);
};
fetch를 이용해서 API의 데이터를 가져온 후에 state에 담는다.
API 링크 https://www.themoviedb.org/
Promise.all
const getData = async () => {
await Promise.all([getNowPlaying(), getTopRated(), getUpcoming()]);
setIsLoading(false);
};
- function 앞에 async를 붙이면 해당 함수는 항상 프라미스를 반환한다. 프라미스가 아닌 값을 반환하더라도 이행 상태의 프라미스(resolved promise)로 값을 감싸 이행된 프라미스가 반환되도록 한다.
- 출처 https://ko.javascript.info/async-await
- Promise.all() 메서드는 순회 가능한 객체에 주어진 모든 프로미스가 이행한 후, 혹은 프로미스가 주어지지 않았을 때 이행하는 Promise를 반환한다. 주어진 프로미스 중 하나가 거부하는 경우, 첫 번째로 거절한 프로미스의 이유를 사용해 자신도 거부한다.
- 출처 https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
RefreshControl-스크롤로 새로고침 처리하기
const [isRefreshing, setIsRefreshing] = useState(false);
const onRefresh = async () => {
setIsRefreshing(true);
await getData();
setIsRefreshing(false);
};
<ScrollView refreshControl={
<RefreshControl refreshing={isRefreshing} onRefresh={onRefresh} />
}>
최상위 <ScrollView> 컴포넌트에 <RefreshControl>을 넣고, isRefreshing state와 onRefresh라는 함수를 이용해서 스크롤을 내렸을 때 새로고침 처리를 할 수 있다.
- refreshing: Whether the view should be indicating an active refresh. (type: boolean)
- onRefresh: Called when the view starts refreshing. (type: function)
공식 문서 https://reactnative.dev/docs/refreshcontrol#onrefresh
<FlatList
refreshing={isRefreshing}
onRefresh={onRefresh}
/>
+) FlatList를 사용할 때는 <RefreshControl>을 따로 사용하지 않아도 된다.
- onRefresh: If provided, a standard RefreshControl will be added for "Pull to Refresh" functionality. Make sure to also set the refreshing prop correctly.
FlatList란?
<FlatList
horizontal
contentContainerStyle={{ paddingHorizontal: 10 }}
showsHorizontalScrollIndicator={false}
data={topRated} //필수 요소
renderItem={({ item }) => <TopRatedCard movie={item} />} //필수 요소
keyExtractor={(item) => item.id}
// ItemSeparatorComponent={ <View style={{ width: 10 }} /> }
/>
- ScrollView: 모든 리스트들을 한번에 렌더링 해야 해서 리스트가 많을수록 성능이 저하된다.
- FlatList: 화면에 보이지 않는 리스트들은 메모리에서 제거하고 화면에 보이는 부분들만 렌더링하여 리스트가 많이 있어도 성능 저하를 최소화시킨다. (무한스크롤 적용에 적합)
주요 Props
- data : 데이터를 받아 올 곳을 입력하는 곳
- renderItem : [data]에서 항목을 가져와 목록으로 렌더링
- keyExtractor : JavaScript에서 'Key'와 같은 기능. 지정된 index에서 지정된 항목의 고유 키를 추출하는 데 사용.
공식 문서 https://reactnative.dev/docs/flatlist
참고 https://velog.io/@st2702/React-Native-FlatList
Liniking으로 링크 연결하기
const openYoutube = async (key) => {
const url = `https://www.youtube.com/watch?v=${key}`;
await Linking.openURL(url);
}
Linking 컴포넌트를 이용해 외부 URL 링크를 열 수 있다. 만약에 유튜브 어플이 설치되어 있다면 바로 어플로 연결되고 설치되어 있지 않다면 웹 브라우저에서 링크가 열린다.
param 받아서 페이지 연결하기
const { navigate } = useNavigation();
<MovieContainer
onPress={() => navigate("Stacks", {
screen: "Detail",
params: { movieId: movie.id }
})}
>
해당 요소를 클릭했을 때 이동할 페이지를 지정하고 params를 넘긴다.
const Detail = ({ navigation: { navigate }, route: { params: { movieId }}}) => {
...생략...
};
클릭했을 때 이동하는 목적지인 컴포넌트는 route에서 params를 받는다.
StatusBar 텍스트 색상 조정하기
const isDark = useColorScheme() === "dark";
<StatusBar style={isDark ? "light" : "dark"} />
다크 모드로 변환했을 때 상단바가 전부 까매져서 시간이나 배터리 부분이 보이지 않아서 StatusBar 컴포넌트를 이용해서 색상을 조정했다. 저 isDark라는 녀석 다크모드 구현할 때 여기저기 유용하게 사용할 수 있다!
Programmers 문제 풀기
아이스 아메리카노
나의 풀이
function solution(money) {
let answer = [];
answer.push(parseInt(money / 5500))
answer.push(money % 5500)
return answer
}
다른 사람의 풀이
function solution(money) {
return [Math.floor(money / 5500), money % 5500];
}
안 그래도 문제 풀면서 배열에 한번에 추가할 수 있는 방법이 없을까 생각했었는데 그냥 배열에 바로 넣으면 되는 거였구나... 이 풀이의 포인트는 배열 안에서 답을 바로 계산했다는 것!
- Math.floor() 함수는 주어진 숫자와 같거나 작은 정수 중에서 가장 큰 수를 반환한다.
회고
어제 UI 지옥에서 벗어나서 오늘은 API 이용해서 가져온 정보를 화면에 뿌려주는 공부를 했는데 이게 훨씬 재밌다. 그나저나 네이티브는 수정할 때마다 에러가 뜬다. 그래도 오늘은 꽤나 집중해서 공부했기 때문에 9시 전에 오늘 분량을 다 마칠 수 있었다. 네이티브 공부하면서 느낀 점이 앱은 페이지 이동이 가장 중요한 부분인 거 같다. 그래도 공부하다 보니까 앱 개발도 매력이 있는 거 같기도 하고.. 흐음...