본문 바로가기
App Study/React Native

노마드코더의 리액트 네이티브 입문 - 2

by 쿠리의일상 2023. 5. 25.

Snack

브라우저에서 리액트 어플리케이션을 만들 수 있게 해주는 온라인 코드에디터 (VSCode를 사용할 수 없는 상황... 아이패드만 있다거나)

https://snack.expo.dev/ 접속!

 


React Native 의 규칙

1. 브라우저가 아니므로 HTML 를 사용할 수 없음

즉, div 등의 태그를 사용할 수 없고, 대신 View 를 사용

View 는 container, div와 동일한 의미로 사용해줄 수 있음

 

import { StyleSheet, Text, View } from 'react-native';

그래서 위처럼 import 해서 사용하는 것...!!

 

 

2. 리액트 네이티브에 있는 모든 text는 text component 에 들어가야 한다

<Text> 안에 넣지 않고 <View> 컴포넌트 안에 텍스트 내용을 넣으면 바로 오류가 발생!

p 태그, span.... 이런 같은 것도 따로 없고 오로지 <Text> 만 존재함!

 

 

3. style 속성은 웹에서 사용하던 일부 style 을 사용할 수 없으며, 스타일링은 위해 StyleSheet.create() 로 스타일 객체를 다루게 됨

export default function App() {
  return (
    <View style={styles.container}>
      <Text>Hello React Native</Text>
      <StatusBar style="auto" />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
});

View 컴포넌트에 style 속성으로 아래의 styles 객체의 container 에 접근하여 스타일링을 주는 형태로 사용해줌!

 

하지만 border 같은 몇몇 스타일링 속성은 사용이 불가함 (98% 이상은 쓸 수 있으나 몇몇이 안되는 것임)

 

여기서 사용된 StyleSheet.create() 메서드는 객체를 생성하는데 사용된다. -> 자동 완성 기능을 지원하므로 스타일링 사용을 선호, 반드시 필요한 것은 아니므로 선택 사항임

+ 객체 형태므로 CSS 방식이 아닌 카멜 네이밍 형식을 사용

 

 


 
import { StatusBar } from 'expo-status-bar';
 

StatusBar 란 시계, 배터리, Wifi 등의 폰의 상단에 위치한 것들을 통틀어 의미하며 

 
<StatusBar style="auto" />
 

형태로 넣어져 있다. 이러한 컴포넌트들을 third party 패키지라고 함

 

 

https://reactnative.dev/docs/components-and-apis

 

Core Components and APIs · React Native

React Native provides a number of built-in Core Components ready for you to use in your app. You can find them all in the left sidebar (or menu above, if you are on a narrow screen). If you're not sure where to get started, take a look at the following cat

reactnative.dev

위의 페이지에서 사용할 수 있는 컴포넌트들을 볼 수 있다.

 

예전 버전의 문서를 확인하면 APIs 와 컴포넌트의 종류가 더 많았음을 알 수 있는데

최신 버전의 문서를 보면 사라진 것들이 있다. (AsyncStorage, Navigation, ...)

그 이유는 모든 컴포넌트를 지원하는게 어렵고(업데이트와 유지보수) 버그가 심했기 때문에 규모를 줄이게 된 것이다.

 

중요한 컴포넌트만 남기고 나머진 위의 StatusBar 같이 커뮤니티 패키지, 즉 다른 서드파티 패키지를 가져다가 써야한다는 것임

 


컴포넌트란?

화면에 렌더링할 항목(return)

 

 

APIs

핸드폰에서 작동하는 자바스크립트 코드를 의미

Vibration 이라는 기능은 진동시키는 기능인데 이런 부분에 사용하는 

vibrate() 이런 것들을 의미함

 

 

 

 


https://reactnative.directory/?search=storage

리액트 네이티브 디렉터리에는 리액트 네이티브에서 사용할 서드파티 패키지와 API가 존재함

리액트 네이티브측에서 모든 컴포넌트를 유지보수 업데이트 생성을 할 수 없기에 다른 사람보고 만들라고 한 것...

그래서 리액트 네이티브의 커뮤니티에 의존하게 될 수밖에 없게 됨

+ Expo Packages 도 커뮤니티를 운영함 (https://docs.expo.dev/versions/latest/sdk/document-picker/#documentpickeroptions)

---> 그래서 위 StatusBar 가 expo에서부터 import 되는지 알 수 있음

 

 


React Native 레이아웃 시스템

웹에서의 Flexbox 와 유사

다만 예외가 존재함

 

일단 앱에선 display: block, inline-block, grid 가 존재하지 않음!!

오로지 flex만 존재함!

 

 

<View> 컴포넌트는 기본적으로 flex로 지정되어 있다.

그리고 flexDirection 의 경우 웹에선 기본 row 지만, 앱에선 기본이 column 이다.***

 

웹과 달리 앱에서 오버플로우된다고 스크롤 되지 않는다.

 

너비와 높이에 기반하여 레이아웃을 만들지 않는다.

그 이유는 다양한 디바이스 크기에 따라 달라보이기 때문이다.

다양한 크기에서 동일한 방식으로 보이는 반응형레이아웃을 만드는 것에 초점을 줘야하므로

레이아웃을 만드는데는 width와 height 를 지양해준다.

 

 

RN 방식으로 레이아웃을 만드는 방법

기본적으로 <View>는 flex 이므로 이를 기준으로 flex의 사이즈를 비율로 주는 방식을 사용한다. (px이나 %를 줄 필요 없다.)

다만 부모의 flex 사이즈의 관계성이 중요한 것이므로 부모 컴포넌트에 flex 크기를 꼭 지정해줘야한다.

  • 부모 flex 를 만들고
  • 자식을 flex의 비율로 조정
export default function App() {
  return (
      <View style={{ flex : 1 }}>
        <View style={{
          flex : 1,
          backgroundColor: 'tomato' }}></View>
        <View style={{
          flex : 1,
          backgroundColor: 'teal',
        }}></View>
        <View style={{
          flex : 1,
          backgroundColor: 'orange',
        }}></View>
      </View>
  );
}

 

 


날씨 앱 만들기 돌입

1. 레이아웃을 만들고 각각의 style 주기

2. 앱은 기본적으로 컴포넌트에 내용이 많아도 스크롤이 되지 않는다 (웹은 오버플로우시 스크롤이 기본)

 

스크롤을 구현하기 위해서 ScrollView 컴포넌트를 사용해준다!

해당 컴포넌트를 사용하면 운영체제(안드로이드나 iOS)에 해당하는 스크롤 효과를 가지게 된다. -> 즉 iOS에서 스크롤 시 구현되는 바운싱은 안드로이드에선 존재하지 않을 수 있다는 것

https://reactnative.dev/docs/scrollview

 

ScrollView · React Native

Component that wraps platform ScrollView while providing integration with touch locking "responder" system.

reactnative.dev

문서에서 볼 수 있듯 많은 속성들이 존재하는데, 이 중에서 스크롤이 세로방향이 아닌 가로방향으로 해주고 싶다면

horizontal 속성을 추가해준다.

 

이때 원래 제작해줬던 flex 사이즈가 먹히지 않음을 볼 수 있음.. 이것은 스크롤뷰 컴포넌트가 style 속성으로 스타일을 줄 수 없음을 알 수 있다. 대신 Container Style 속성을 사용하도록 한다.

contentContainerStyle 속성은 style 과 달리 flex 사이즈를 줄 필요가 없기 때문에(당연히 스크롤이 되는 부분은 원래 컨텐츠 크기보다 커야하므로) flex 사이즈를 주지 않는다. 주면 스크롤이 이상한 곳에서 끊기게 된다.

m 을 누르면(스마트폰의 경우 흔들면) 개발자 메뉴가 뜨는데 그중 show element inspector 는 브라우저에서 개발자 도구의 element 탭과 동일하다고 생각하면 된다.

element inspector 를 없애주고 싶다면 m을 누르고 Hide element inspector 해주자.

 

 

이제 스크롤에서 온도와 날씨부분을 디바이스의 가로 전체화면 길이만큼 지정해주고 싶다.

이를 위한 API가 존재하는데 Dimensions 이다.

https://reactnative.dev/docs/dimensions

 

Dimensions · React Native

useWindowDimensions is the preferred API for React components. Unlike Dimensions, it updates as the window's dimensions update. This works nicely with the React paradigm.

reactnative.dev

 

import { Dimensions } from 'react-native';

const { height, width } = Dimensions.get('window');

 

위의 스크린샷과 달리 스크롤 해줄 수 있게끔 날씨부분에 width를 디바이스의 크기를 가져와서 스크롤을 해야 보이게 해주었다.

다만 스크롤이 지금은 너무 자유롭기 때문에 스크롤뷰의 pagingEnable 속성을 사용해준다.

그럼 위의 자유분방한 스크롤은 페이지화 되어 sticky 하게 스크롤 될 것이다.

 

스크롤뷰의 기본인 pagination 을 숨기는 방법도 존재한다.

반대는 showsVerticalScrollIndicator 이다.

문서를 보면 기본값이 true 이므로 앱의 아래쪽에 indicator 가 보이는 것이므로 false 로 바꿔주면 보이지 않는다.

 

indicator의 style 을 바꿔주는 방법은 아래의 속성으로 가능한데 iOS만 가능하다.

이렇게 공식 문서를 확인하면서 속성을 사용해준다!

기본적인 디자인은 이렇게 끝내준다

 

3. 휴대폰의 지리적 위치를 가져오는 Location Expo Package 를 사용하기 위해 expo-location 을 설치

https://docs.expo.dev/versions/latest/sdk/location/#enabling-emulator-location

 

Location

Expo is an open-source platform for making universal native apps for Android, iOS, and the web with JavaScript and React.

docs.expo.dev

npx expo install expo-location

 

 

문서에 나온대로 일단 권한 설정부터 해준다.

import * as Location from 'expo-location';

// ...
  const [location, setLocation] = useState(null);
  const [errorMsg, setErrorMsg] = useState(null);
  const ask = async() => {
    let permission = await Location.requestPermissionsAsync();

  }

  useEffect(() => {
    ask();
  }, []);

useState 로 위치 상태를 관리해주고 useEffect로 앱이 실행되면 requestPermissionAsync() 를 통하여 사용자로부터 위치를 받아올 수 있는 권한여부를 받아올 수 있게 해준다.

여기서 requestPermissionAsync 는 이제 사용되지 않으므로 requestForegroundPermissionAsync (앱 사용 중에만 위치를 사용) 혹은 requestBackgroundPermissionAsync 함수를 사용해준다.

 

리턴값인 permission은 아래와 같은 값을 반환한다.

여기서 granted 부분이 허가를 받았는지 여부이므로

 

-----> granted 가 true면 해당 위치에 날씨를

-------> false면 예외처리를

UI가 바뀔 수 있도록 state 를 변경해줘야 한다.

 

const [location, setLocation] = useState(null);
const [ok, setOk] = useState(true);
const ask = async() => {
	const {granted} = await Location.requestForegroundPermissionsAsync();

	// 권한을 받지 못했을 때
	if(!granted) {
  		setOk(false);
	}

	// 권한을 성공적으로 받으면

}

useEffect(() => {
	ask();
}, []);

 

권한을 받은 경우 사용자 위치 정보를 받아와야 한다. 이때는 getCurrentPositionAsync 함수를 사용해준다!

    const location = await Location.getCurrentPositionAsync({
      accuracy : 5,
    })

옵션 내용을 확인해보면 accuracy 부분은 정확성의 영역이다.

location 값으로 받아오는 객체로는 위와 같고, 위치에 따른 날씨 정보를 얻기 위해선

위의 정보 중에서 longitude 와 latitude 가 필요하다.

그러므로 아래처럼 수정해주면 되고

    const {coords :{latitude, longitude}} = await Location.getCurrentPositionAsync({
      accuracy : 5,
    });
    console.log(latitude, longitude);

위도 경도를 통하여 reverse geocoding 을 해줄 수 있는데,

const location = await Location.reverseGeocodeAsync(
	{latitude, longitude}, 
    {useGoogleMaps: false});

이상하게 자꾸 초과된 요청을 보낸다는 에러가 발생했는데 시뮬레이터랑 VSCode 모두 재부팅하고나니 사라졌다. (...?)

 

시뮬레이터로 돌린 location은 미국으로 잡힌다고 한다. 휴대폰은 제대로 잡힌다고 함.

해당 location 정보로 city에 해당하는 state 를 저장한다.

 

그다음 날씨 정보를 array state에 저장할 것인데...

open wheather API 사이트를 사용해준다고 한다.