앱개발 종합반 2주차 개발일지
JSX문법은 정말 간단하게, 화면의 구역을 잡을 때는 <View> 태그를, 글자를 쓸때는 <Text> 태그를 사용하라는 것처럼, 용도에 맞는 태그를 정해놨습니다.
//잠시 살펴보는 JSX !!!
//이렇게 상단에서 사용할 엘리먼트를 react-native 라이브러리로부터 꺼내 사용합니다.
import { Text, View } from 'react-native';
<View>
<Text>Hello, I am {props.name}!</Text>
</View>
Expo란?
[앱 개발 준비] 리액트 네이티브 & Expo 설치하기
Node & NPM 설치
Node.js로 자바스크립트 개발 환경을 구축하고, NPM으로 필요한 자바스크립트 앱 개발 도구들을 가져와 사용하는 모습이라 보면 됩니다.
Yarn
맥은 terminal, 윈도우는 cmd 검은 창에 다음과 같이 순서대로 입력해보도록 하겠습니다
//도구를 가져와 설치하는 npm 의 설치 명령어 install과
//컴퓨터 어디서든 설치하고 있는 도구를 사용할 수 있게 해주는 -g 옵션 명령어 npm install -g yarn
//설치가 완료된다음 yarn -v
yarn은 npm 보다 가볍고 빠르게 자바스크립트 패키지를 관리 할 수 있게 해주는 자바스크립트 패키지 매니저 툴입니다. 각자의 장단점이 있지만, 우린 앞으로 패키지 관리자로 yarn을 좀 더 많이 사용하게 됩니다.
Expo 명령어 도구 설치
맥 사용자분들은 npm 명령으로 도구들을 설치할 때 "permission denied"라는 오류가 발생하면, 당황하지말고 sudo를 앞에 붙여주세요 sudo npm install -g expo-cli 여러분들 컴퓨터 깊숙이 설치하는 과정이라 권한이 없다는 이야기로 보시면 됩니다! 그럴때 sudo를 앞에 붙여 나 이 컴퓨터 주인이다! 라고 알려주시면 돼요!
[Windows] 윈도우를 사용하는데 expo init 또는 expo start 를 진행하니 expo : 이 시스템에서 스크립트를 실행할 수 없으므로 C:\Users\PC\AppData\Roaming\npm\expo.ps1 파일을 로드할 수 없습니다. 오류가 발생합니다. (영어 윈도우: expo : File C:\Users\PC\AppData\Roaming\npm\expo.ps1 cannot be loaded because running script is disabled on this system. )
npm install -g expo-cli
이 명령어 한 줄은 이런 의미가 담겨 있습니다.
npm: 노드 패키지 매니저 명령을 실행하겠다
install: 설치하겠다
-g: 컴퓨터 전역적으로 설치하겠다 == 어디서든지 -g 다음에 오는 명령어를 사용할 수 있게끔!
expo-cli: 설치 할 패키지 이름 따라서 우린 이 명령어 한 줄로, 여러분 컴퓨터 어디서든지 Expo를 사용할 수 있게끔 패키지를 전역적으로 설치했습니다.
Expo를 설치 및 사용한다는 것은, Expo가 기본적으로 제공해주는 명령어들...
1) 프로젝트 생성,
2) 프로젝트 실행,
3) 프로젝트 빌드 등등의 여러 기능들을 사용 할 수 있다는 것을 뜻합니다.
Expo 가입 및 로컬에 Expo 계정 세팅
1)Expo 가입
Sign Up — Expo
Create an account for Expo here.
expo.dev
Expo로 개발중인 앱을 마켓에 배포하기 위해선 여러분들 컴퓨터에 Expo 계정을 세팅해야 합니다 그래야 추후에 배포 앱 관리와 배포를 한번에! 진행할 수 있습니다
2) 로컬에 Expo 계정 세팅
Expo 계정을 생성했으면, 여러분들 컴퓨터에 Expo 계정을 연결시켜줘야 합니다. 어려운일은 아니고 여러분 컴퓨터로 해당 계정으로 로그인을 하면되는데요! 윈도우는 cmd 맥은 terminal에서 다음 명령어를 실행합니다.
expo login ... expo 이메일(또는 아이디), 패스워드 입력란이 차례로 나오고, 차례대로 입력하면 로그인 성공!
[앱 개발 준비] Expo 실행하기
expo는 Expo 명령어를 사용하겠다. init은 Expo 앱을 생성하는 Expo 명령어! sparta-myhoneytip-영어이름은 앱 이름! 영어이름엔 여러분들 영어이름을 넣어주세요 가령 sparta-myhoneytip-gun 처럼요!
cd sparta-myhoneytip-gun
cd <폴더명> : change directory의 약자로 입력한 폴더명으로 이동하는 명령어입니다.
expo start
expo start 명령어를 실행하면 터미널에 Expo 실행이 진행되며, 자동으로 브라우저가 열리면서 Expo 앱을 열 준비를 합니다. expo start 명령어는 Expo 서버를 킨 것과 동일합니다. Expo 서버를 킨다는 것은 현재 개발하고 있는 앱을 실행시킨다는 뜻과 같습니다.. 반대로 서버를 끌땐?
윈도우 : 컨트롤 + c
맥 : command + c
expo start명령어 실행 결과를 보면, QR코드가 나타나는 것을 볼 수 있습니다. 여러분들 휴대폰에 Expo 클라이언트 앱이 설치되어 있단 가정하에, 휴대폰 카메라로 저 QR코드를 인식해보시기 바랍니다. 그럼 여러분들 휴대폰에 설치되어 있는 Expo 클라이언트 앱을 열까? 라고 물어보며 켜줘!라고 클릭을 하게되면, 지금 컴퓨터에서 여러분들이 expo start로 실행시킨 Expo 서버 위에서 돌아가고 있는 Expo 앱을 휴대폰에서, 더 정확히는 Expo 클라이언트 앱에서 확인 할 수 있습니다.
2. 연결이 안될때
(1) 컴퓨터가 연결된 와이파이와 앱을 실행시키는 휴대폰에 연결된 와이파이가 동일한지!
(2) 왼쪽 하단 QR 코드 위에 , Tunnel, Lan, Local 모두 눌러보면서 되는 환경을 찾아보기! (2)의 이유는, 각 컴퓨터 마다 환경 설정이 다르기 때문입니다. 방화벽이 그 이유일 수도 있구요! 네트워크 환경이 다를 수도 있습니다. 그렇기 때문에, 정상적으로 실행되는 환경을 찾아보시길 추천 드립니다!
가상기기 만들기 및 관리하기
https://developer.android.com/studio/run/managing-avds?hl=ko
가상 기기 만들기 및 관리하기 | Android 개발자 | Android Developers
Android 스튜디오에서 가상 기기를 만들고 관리하는 방법에 관해 알아보세요.
developer.android.com
Run on Android device/emulator:
컴퓨터와 USB로 연결된 안드로이드 휴대폰 또는 우리가 설치한 안드로이드 시뮬레이터로 Expo을 실행시키는 버튼
Run on iOS simulator:
설치한 iOS 시뮬레이터로 Expo 앱을 실행시키는 버튼
Run in web browser:
작업중인 Expo 앱을 브라우저에서 확인 하는 버튼. 즉, 웹 플랫폼에 대응 하게끔 지원
왼쪽 버튼 중에서 Run in web browser를 눌러보면!
Send link with email
작업 중인 Expo 앱은 Expo 클라이언트 앱이 설치되어 있는 휴대폰 어디서든 실행할 수 있습니다. 즉 이 때 개발중인 Expo앱 링크를 통해서도 바로 Expo 클라이언트 앱으로 개발중인 앱 확인이 가능합니다.
Public or republish project
강의 초반에 리액트 네이티브&Expo는 안드로이드, IOS, 웹 세 플랫폼에 대응하는 애플리케이션을 만들 수 있다고 언급한 바 있습니다. 바로 지금 우리는 세 플랫폼 중 웹에서 애플리케이션을 띄워 본겁니다!. 정말 간단하죠? 그런데 expo start명령어 실행 결과를 보면, QR코드가 나타나는 것을 볼 수 있습니다. 여러분들 휴대폰에 Expo 클라이언트 앱이 설치되어 있단 가정하에, 휴대폰 카메라로 저 QR코드를 인식해보시기 바랍니다. 그럼 여러분들 휴대폰에 설치되어 있는 Expo 클라이언트 앱을 열까? 라고 물어보며 켜줘!라고 클릭을 하게되면, 지금 컴퓨터에서 여러분들이 expo start로 실행시킨 Expo 서버 위에서 돌아가고 있는 Expo 앱을 휴대폰에서, 더 정확히는 Expo 클라이언트 앱에서 확인 할 수 있습니다.
또한 expo start 명령어를 실행시켰을 때, 자동적으로 열렸던 크롬 브라우저의 expo 개발자 도구 화면에서 우측 상단의 버튼을 누르면 다음과 같이 화면이 분할 되면서 Expo 웹 플랫폼 앱과 현재 여러분 휴대폰에서 실행되고 있는 앱 플랫폼에 대한 상태 로그들을 동시에 확인 할 수 있게 됩니다.
2) 안드로이드에 시뮬레이터 설치
- 먼저 https://developer.android.com/studio(안드로이드 스튜디오)에 Android Studio를 가셔서 다운받으세요. 실행시키면 아래와 같은 화면이 나옵니다.
expo start --android
expo start와 동일하지만, Expo 서버를 켠다음 동시에 안드로이드 시뮬레이터를 작동시킵니다.
expo init으로 프로젝트를 생성하면 Expo로 부터 기본 골격이 짜여져 있는 코드 다발을 받게되는 셈입니다.
[앱 화면 만들기] JSX 문법
//우리가 리액트, 리액트 네이티브, 엑스포 라이브러리에서 꺼내 사용할 기능들을
//이렇게 앞으로도 상단에 선언한다음 가져다 사용합니다.
import { StatusBar } from 'expo-status-bar';
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
//App.js는 결국 App 함수를 내보내기 하고 있는 자바스크립트 파일입니다.
//이 함수는 무언가?를 반환하고 있는데 결국 화면을 반환하고 있습니다.
export default function App() {
//화면을 반환합니다.
//HTML 태그 같이 생긴 이 문법은 JSX라 불리우며 실제 화면을 그리는 문법입니다,
//이번 강의에서 자세히 다룹니다
return (
<View style={styles.container}>
<Text>Open up App.js to start working on your app!</Text>
<StatusBar style="auto" />
</View>
);
}
// styles 변수 이름 답게 화면을 그려주는,
//더 자세히는 JSX문법을 꾸며주는 내용을 담고 있습니다.
const styles = StyleSheet.create({
container: { flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center', }, });
노란색 경고창 안보이게 하기
//우리가 리액트, 리액트 네이티브, 엑스포 라이브러리에서 꺼내 사용할 기능들을
//이렇게 앞으로도 상단에 선언한다음 가져다 사용합니다.
import { StatusBar } from 'expo-status-bar';
import React from 'react';
import { StyleSheet, Text, View, Logbox } from 'react-native';
//App.js는 결국 App 함수를 내보내기 하고 있는 자바스크립트 파일입니다.
//이 함수는 무언가?를 반환하고 있는데 결국 화면을 반고 있습니다.
export default function App() {
//화면을 반환합니다.
//HTML 태그 같이 생긴 이 문법은 JSX라 불리우며 실제 화면을 그리는 문법입니다,
//이번 강의에서 자세히 다룹니다
LogBox.ignoreLogs(['Warning: ...']); ⇒ 노란색 경고창이 안보이게 하는 부적같은 존재
return (
<View style={styles.container}>
<Text>Open up App.js to start working on your app!</Text>
<StatusBar style="auto" />
</View>
);
}
// styles 변수 이름 답게 화면을 그려주는,
//더 자세히는 JSX문법을 꾸며주는 내용을 담고 있습니다.
const styles = StyleSheet.create({
container: {
lex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
[앱 화면 만들기] JSX 기본 문법
https://reactnative.dev/docs/view?redirected
View · React Native
The most fundamental component for building a UI, View is a container that supports layout with flexbox, style, some touch handling, and accessibility controls. View maps directly to the native view equivalent on whatever platform React Native is running o
reactnative.dev
import { StatusBar } from 'expo-status-bar';
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
export default function App() {
return (
<View style={styles.container}>
<Text>Open up App.js to start working on your app!</Text>
<StatusBar style="auto" />
</View>
);
}
태그는 항상 닫는 태그와 자체적으로 닫는 태그를 구분해서 사용해야 함!
export default function App() { return (
//<View>는 결국 두번째 줄 밑에 </View>로 닫히면서 본인 영역을 갖습니다
<View style={styles.container}>
<Text>Open up App.js to start working on your app!</Text>
//statusBar는 본인 스스로 닫는 태그이므로 다음과 같이 사용이 가능합니다.
<StatusBar style="auto" />
</View>
);
}
- 리액트 네이티브 공식 문서 https://reactnative.dev/docs/view
- Expo 공식 문서 https://docs.expo.io/versions/v38.0.0/react-native/view/
모든 엘리먼트는 감싸는 최상위 엘리먼트가 있어야 함. 엘리먼트는 곧! 태그 <> 입니다
//App.js가 렌더링 하고 엘리먼트는 결국
//Text와 StatusBar엘리먼트를 감싸고 잇는 View입니다.
export default function App() {
return ( <View style={styles.container}>
<Text>Open up App.js to start working on your app!</Text>
<StatusBar style="auto" />
</View>
);
}
다음과 같이 감싸는 엘리먼트가 없다면 오류가 발생합니다.
//View 엘리먼트 밖에 StatusBar가 나와 있으므로 엘리먼트 전체를 감싸는 엘리먼트가
//없어서 오류가 납니다.
export default function App() {
return ( <View style={styles.container}>
<Text>Open up App.js to start working on your app!</Text>
</View>
<StatusBar style="auto" /> ); }
꼭 감싸는 엘리먼트 없이 , 혹은 추후 디자인적인 측면을 위해 없이 진행해야 한다면, 다음과 같이 프래그먼트라는 의미없는 엘리먼트로 감싸서 렌더링 할 수도 있습니다.
export default function App() { return ( <> <View style={styles.container}> <Text>Open up App.js to start working on your app!</Text> </View> <StatusBar style="auto" /> </> ); }
return에 의해 렌더링 될 땐 항상 소괄호로 감싸져야 한다.
return 구문으로 엘리먼트를 렌더링(반환) 할 때 소괄호로 항상 감싸여 있었습니다.
JSX 문법 밖에서의 주석과 안에서의 주석은 다르다!
//JSX밖에서의 주석
import { StatusBar } from 'expo-status-bar';
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
//JSX밖에서의 주석 export default function App() {
//JSX밖에서의 주석
return (
//JSX 밖에서의 주석 <View style={styles.container}> {/* JSX 문법 안에서의 주석 */}
<Text>Open up App.js to start working on your app!</Text>
<StatusBar style="auto" />
</View>
);
}
//JSX밖에서의 주석
const styles = StyleSheet.create({
container: { flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
[앱 화면 만들기] View, Text, ScrollView
<View></View> 화면의 영역(레이아웃)을 잡아주는 엘리먼트입니다.
현재 App.js 상에서 View는 화면 전체 영역을 가집니다. 우리는 이 View 엘리먼트로 다음과 같이 화면을 원하는 대로 분할 할 수도 있습니다.
import { StatusBar } from 'expo-status-bar';
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
export default function App() {
return (
<View style={styles.container}>
<View style={styles.subContainerOne}></View>
<View style={styles.subContainerTwo}></View>
</View>
);
}
const styles = StyleSheet.create({ container: {
flex: 1,
backgroundColor: '#fff',
},
subContainerOne: {
flex:1,
backgroundColor:"yellow"
},
subContainerTwo: {
flex:1,
backgroundColor:"green"
}
});
<Text>태그 사용법
<ScrollView>태그 사용법
앱 화면을 벗어나는 영역의 경우 ScrollView 엘리먼트로 감싸면 스크롤이 가능해지면서 모든 컨텐츠를 볼 수 있습니다.
import React from 'react'; import { StyleSheet, Text, View } from 'react-native'; export default function App() { return ( //각 태그들에는 style이라는 속성을 갖습니다.
//이 속성은 파일 최하단에 작성한 스타일 코드 객체의 키 값을 부여해
// 엘리먼트들에 스타일을 줄 수 있습니다.
//이는 JSX문법을 배우고 난 다음 더 자세히 다룹니다.
<View style={styles.container}> {/* //보인 영역을 갖는 엘리먼트 7가 반복적으로 쓰였습니다. */}
<View style={styles.textContainer}> <Text style={styles.textStyle}>영역을 충분히 갖는 텍스트 입니다!</Text> </View> <View style={styles.textContainer}> <Text style={styles.textStyle}>영역을 충분히 갖는 텍스트 입니다!</Text> </View> <View style={styles.textContainer}> <Text style={styles.textStyle}>영역을 충분히 갖는 텍스트 입니다!</Text> </View> <View style={styles.textContainer}> <Text style={styles.textStyle}>영역을 충분히 갖는 텍스트 입니다!</Text> </View> <View style={styles.textContainer}> <Text style={styles.textStyle}>영역을 충분히 갖는 텍스트 입니다!</Text> </View> <View style={styles.textContainer}> <Text style={styles.textStyle}>영역을 충분히 갖는 텍스트 입니다!</Text> </View> <View style={styles.textContainer}> <Text style={styles.textStyle}>영역을 충분히 갖는 텍스트 입니다!</Text> </View> </View>
);
}
//텍스트가 영역을 갖고, 가운데 정렬도 하며, 테두리 스타일을 갖게 끔 하는 코드입니다.
//JSX를 마저 배우고 스타일에 대해 자세히 다루니
//걱정 안해도 좋습니다!
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
},
textContainer: {
height:100,
borderColor:'#000',
borderWidth:1,
borderRadius:10,
margin:10,
},
textStyle: {
textAlign:"center"
}
});
ScrollView를 상단에서 불러온다음 전체 엘리먼트를 View아닌 ScrollView로 감싸보세요 그러면 화면이 스크롤되면서 가려진 영역을 볼 수 있습니다.
ScrollView -2
import React from 'react';
import { StyleSheet, Text, View, ScrollView } from 'react-native';
export default function App() {
return (
<ScrollView style={styles.container}>
<View style={styles.textContainer}> <Text style={styles.textStyle}>영역을 충분히 갖는 텍스트 입니다!</Text> </View> <View style={styles.textContainer}> <Text style={styles.textStyle}>영역을 충분히 갖는 텍스트 입니다!</Text> </View> <View style={styles.textContainer}> <Text style={styles.textStyle}>영역을 충분히 갖는 텍스트 입니다!</Text> </View> <View style={styles.textContainer}> <Text style={styles.textStyle}>영역을 충분히 갖는 텍스트 입니다!</Text> </View> <View style={styles.textContainer}> <Text style={styles.textStyle}>영역을 충분히 갖는 텍스트 입니다!</Text> </View> <View style={styles.textContainer}> <Text style={styles.textStyle}>영역을 충분히 갖는 텍스트 입니다!</Text> </View> <View style={styles.textContainer}> <Text style={styles.textStyle}>영역을 충분히 갖는 텍스트 입니다!</Text> </View> </ScrollView>
);
}
const styles = StyleSheet.create({
container:
{ flex: 1,
backgroundColor: '#fff',
},
textContainer: {
height:100,
borderColor:'#000',
borderWidth:1,
borderRadius:10,
margin:10,
},
extStyle: {
textAlign:"center"
}
});
[앱 화면 만들기] Button, Image
<Button>과 함수
import React from 'react';
import { StyleSheet, Text, View, Button, Alert } from 'react-native';
export default function App() {
return (
<View style={styles.container}>
<View style={styles.textContainer}>
<Text style={styles.textStyle}>아래 버튼을 눌러주세요</Text>
{/* 버튼 onPress 속성에 일반 함수를 연결 할 수 있습니다.*/}
<Button
style={styles.buttonStyle}
title="버튼입니다 "
color="#f194ff"
onPress={function(){
Alert.alert('팝업 알람입니다!!')
}}
/>
{/* ES6 문법으로 배웠던 화살표 함수로 연결 할 수도 있습니다. */}
<Button
style={styles.buttonStyle}
title="버튼입니다 "
color="#FF0000"
onPress={()=>{
Alert.alert('팝업 알람입니다!!')
}}
/>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
},
textContainer: {
height:100,
margin:10,
},
textStyle: {
textAlign:"center"
},
});
- 버튼 설명서 https://reactnative.dev/docs/button
- 팝업 알람(Alert) 설명서 https://reactnative.dev/docs/alert#docsNav
Button 태그를 예로 들면, 버튼 안에 잇는 문자는 title이란 속성에 값을 넣어서 구현 할 수 있고, 버튼 색상은 color 속성에 값을 넣어서 적용 할 수 있습니다. 눌렀을 때 어떤 이벤트가 일어나게 하려면 onPress에 함수를 연결(바인딩)하면 되는데, 이 부분을 좀 더 살펴보겠습니다.
import React from 'react'; import { StyleSheet, Text, View, Button, Alert } from 'react-native';
export default function App() {
return (
<View style={styles.container}>
<View style={styles.textContainer}>
<Text style={styles.textStyle}>아래 버튼을 눌러주세요</Text>
{/* 버튼 onPress 속성에 일반 함수를 연결 할 수 있습니다. */}
<Button style={styles.buttonStyle}
title="버튼입니다 "
color="#f194ff"
onPress={
function(){
Alert.alert('팝업 알람입니다!!')
}}
/>
{/* ES6 문법으로 배웠던 화살표 함수로 연결 할 수도 있습니다. */}
<Button style={
styles.buttonStyle
}
title="버튼입니다 "
color="#FF0000"
onPress={()=>{
Alert.alert('팝업 알람입니다!!')
}}
/>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
},
textContainer: {
height:100,
margin:10,
},
textStyle: {
textAlign:"center"
},
});
onPress에 연결한 함수 구현부를 JSX 밖에서 구현한 다음 연결 할 수도 있습니다. 그땐 화살표 함수로 구현하여 함수를 만든 다음 연결해야 합니다.
import React from 'react';
import { StyleSheet, Text, View, Button, Alert } from 'react-native';
export default function App() {
//화살표 함수 형식으로 함수를 정의하고
//jSX문법 안에서 사용할 수 있습니다
const customAlert = () => {
Alert.alert("JSX 밖에서 함수 구현 가능!")
}
return ( <View style={styles.container}>
<View style={styles.textContainer}>
<Text style={styles.textStyle}>아래 버튼을 눌러주세요</Text>
{/* onPress에 밖에서 구현한 함수 이름을 고대로 넣을 수도 있고*/}
<Button style={styles.buttonStyle}
title="버튼입니다 "
color="#f194ff"
onPress={customAlert} />
{/* onPress를 누르면 속성에 바로 구현해 놓은 함수 안에 customALert함수를 두고 실행할 수 있게도 가능합니다 */} <Button style={styles.buttonStyle}
title="버튼입니다
" color="#FF0000"
onPress={() => {customAlert()}} />
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
},
textContainer: {
height:100,
margin:10, },
textStyle: {
textAlign:"center"
},
});
<TouchableOpacity/>
<aside> 💡 Button 엘리먼트는 본인의 영역을 갖습니다. 그렇기 때문에 스타일에도 신경을 써야 하고 ScrollView에서 처럼 카드 형식으로 만든 다음 화면 같은 경우엔 버튼 태그를 사용하기 어렵습니다.
저 영역을 충분히 갖는 텍스트 카드 부분을 눌러야 할 때 말이죠!
</aside>
ScrollView 코드를 다시 App.js에 옮기고 다음과 같이 각 카드의 View 부분을 TouchableOpacity로 변경해보겠습니다.
import React from 'react';
import { StyleSheet, Text, View, ScrollView, TouchableOpacity, Alert } from 'react-native';
export default function App() {
const customAlert = () => {
Alert.alert("TouchableOpacity에도 onPress 속성이 있습니다")
}
return (
<ScrollView style={styles.container}>
<TouchableOpacity style={styles.textContainer} onPress={customAlert}>
<Text style={styles.textStyle}>영역을 충분히 갖는 텍스트 입니다!</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.textContainer} onPress={customAlert}>
<Text style={styles.textStyle}>영역을 충분히 갖는 텍스트 입니다!</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.textContainer} onPress={customAlert}>
<Text style={styles.textStyle}>영역을 충분히 갖는 텍스트 입니다!</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.textContainer} onPress={customAlert}>
<Text style={styles.textStyle}>영역을 충분히 갖는 텍스트 입니다!</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.textContainer} onPress={customAlert}>
<Text style={styles.textStyle}>영역을 충분히 갖는 텍스트 입니다!</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.textContainer} onPress={customAlert}>
<Text style={styles.textStyle}>영역을 충분히 갖는 텍스트 입니다!</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.textContainer} onPress={customAlert}>
<Text style={styles.textStyle}>영역을 충분히 갖는 텍스트 입니다!</Text>
</TouchableOpacity>
</ScrollView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
},
textContainer: {
height:100,
borderColor:'#000',
borderWidth:1,
borderRadius:10,
margin:10, },
textStyle: {
textAlign:"center"
}
});
<Image>
두 가지 방식이 있습니다. assets 폴더에 있는 이미지를 가져와서 사용하는 방법과 (import), 외부 이미지 링크를 넣어서 사용하는 방식입니다(uri)
assets 폴더에 있는 이미지 가져와 사용하기
import React from 'react';
import { StyleSheet, Text, View, Image } from 'react-native';
//이렇게 상단에 가져와 사용할 이미지를 불러옵니다
import favicon from "./assets/favicon.png"
export default function App() {
return (
<View style={styles.container}>
{/*이미지 태그 soruce 부분에 가져온 미지 이름을 넣습니다 */}
<Image source={favicon}
// 사용설명서에 나와 있는 resizeMode 속성 값을 그대로 넣어 적용합니다
resizeMode={"repeat"}
style={styles.imageStyle} />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
//혹시 미리 궁금하신 분들을 위해 언급하자면,
//justifyContent와 alignContent는 영역 안에 있는 콘텐츠들을 정렬합니다
justifyContent:"center",
alignContent:"center"
},
imageStyle: {
width:"100%",
height:"100%",
alignItems:"center",
justifyContent:"center"
}
});
캡쳐를 보면 로고가 여러번 반복되어 있는데, 그 이유는 <Image>태그의 resizeMode 속성에 repeat을 줬기 때문입니다. 다른 속성 값을 넣으면 어떻게 될까요? 사용 설명서를 보고 적용해보세요
-Image 태그 사용 설명서
https://reactnative.dev/docs/image#docsNav
Image · React Native
A React component for displaying different types of images, including network images, static resources, temporary local images, and images from local disk, such as the camera roll.
reactnative.dev
외부 이미지 사용하기
외부 이미지를 사용할 땐 source 부분에 uri를 사용하면 됩니다. 다음과 같이 말이죠! 그리고 resizemode 에 방금전 사용했던 repeat 말고 cover라는 값을 넣어봤습니다!
import React from 'react';
import { StyleSheet, Text, View, Image } from 'react-native';
//이렇게 상단에 가져와 사용할 이미지를 불러옵니다
import favicon from "./assets/favicon.png"
export default function App() {
return ( {/*이미지 태그 soruce 부분에 가져온 미지 이름을 넣습니다 */}
https://images.unsplash.com/photo-1424819827928-55f0c8497861?fit=crop&w=600&h=600%27'}}
// 사용설명서에 나와 있는 resizeMode 속성 값을 그대로 넣어 적용합니다
resizeMode={"cover"}
style={styles.imageStyle} />
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
//혹시 미리 궁금하신 분들을 위해 언급하자면,
//justifyContent와 alignContent는 영역 안에 있는 콘텐츠들을 정렬합니다
justifyContent:"center",
alignContent:"center"
},
imageStyle: {
width:"100%",
height:"100%",
alignItems:"center",
justifyContent:"center"
}
});
[앱 화면 만들기] 구성한 화면 꾸미기, Styles
모든 태그에 공통적으로 있는 styles 속성
태그에 스타일을 주는 방식 또한 리액트 네이티브에서 제공하는 StyleSheet 기능을 가져와 적용합니다. 이 StyleSheet은 결국 객체(딕셔너리)를 하나 만드는데, 이쁜 옷들을 정리해 놓는 객체 입니다. 이 객체에 옷을 사용법 대로 생성한 다음 잘 정리해 두고, JSX 엘리먼트에서 사용 하면 됩니다
사용할 땐 모든 태그에 공통적으로 있는 style 속성에 아래서 만든 객체 키값을 부여하여 적용 합니다. 가장 바깥에 있는 View 태그를 보면 다음과 같이 styles 속성에 styles 객체 container 키를 연결한 것을 확인 할 수 있습니다. <View style={styles.container}> 이렇게 영역에 옷을 입혀주기만 하면 이쁜 화면이 나옵니다.
화면을 꾸며주는 StyleSheet 문법
import React from 'react';
import { StyleSheet, Text, View, Image } from 'react-native';
export default function App() {
return (
<View style={styles.container}>
<View style={styles.textContainer}>
<Text style={styles.textStyle}>스파르타 코딩클럽!!</Text>
</View>
</View>
);
}
const styles = StyleSheet.create({ container: {
//영역을 잡는 속성입니다. 따로 자세히 다룹니다.
//flex: 1은 전체 화면을 가져간다는 뜻입니다
flex: 1,
//영역의 배경 색을 결정합니다
backgroundColor: '#fff',
//아래 두 속성은 영역 안의 컨텐츠들의 배치를 결정합니다.
//flex를 자세히 다룰때 같이 자세히 다룹니다
justifyContent:"center",
alignContent:"center"
},
textContainer: {
//영역의 바깥 공간 이격을 뜻합니다(하단 이미지 참조)
margin:10,
//영역 안의 컨텐츠 이격 공간을 뜻합니다(하단 이미지 참조)
padding: 10,
//테두리의 구부러짐을 결정합니다. 지금 보면 조금 둥글죠?
borderRadius:10,
//테두리의 두께를 결정합니다
borderWidth:2,
//테두리 색을 결정합니다 borderColor:"#000",
//테구리 스타일을 결정합니다. 실선은 solid 입니다
borderStyle:"dotted",
},
textStyle: {
//글자 색을 결정합니다. rgb, 값 이름, 색상코드 모두 가능합니다
color:"red",
//글자의 크기를 결정합니다
fontSize:20,
//글자의 두께를 결정합니다 fontWeight:"700",
//가로기준으로 글자의 위치를 결정합니다
textAlign:"center"
}
});
margin과 padding은 다음 이미지들 처럼, 영역의 바깥과 안의 여백을 결정합니다. 그럼 margin과 padding을 늘려보고 줄여보면서 확인해보세요!
-스타일 공식 문서
https://reactnative.dev/docs/style#docsNav
Style · React Native
With React Native, you style your application using JavaScript. All of the core components accept a prop named style. The style names and values usually match how CSS works on the web, except names are written using camel casing, e.g. backgroundColor rathe
reactnative.dev
https://reactnative.dev/docs/layout-props
Layout Props · React Native
More detailed examples about those properties can be found on the Layout with Flexbox page.
reactnative.dev
[앱 화면 만들기] 콘텐츠의 위치: Flex
영역을 차지하는 속성입니다.
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
export default function App() {
return (
<View style={styles.container}>
<View style={styles.containerOne}>
</View>
<View style={styles.containerTwo}>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex:1
},
containerOne: {
flex:1,
backgroundColor:"red"
},
containerTwo:{
flex:2,
backgroundColor:"yellow"
}
});
가장 최상위의 container 스타일을 가져가는 View 엘리먼트는 디바이스 전체 화면의 영역을 가져갑니다. 안 쪽의 containerOne 스타일이 부여된 View 엘리먼트는 전체를 3등분한 뒤 1/3을 가져가고 containerTwo는 2/3를 가져갑니다. 즉, 같은 레벨의 엘리먼트들의 flex 합을 각자의 flex 속성값 대로 가져갑니다.
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
export default function App() {
return (
<View style={styles.container}>
<View style={styles.containerOne}>
</View>
<View style={styles.containerTwo}>
<View style={styles.innerOne}>
</View>
<View style={styles.innerTwo}>
</View>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex:1
},
containerOne: {
flex:1,
backgroundColor:"red"
},
containerTwo:{
flex:2,
backgroundColor:"yellow"
},
innerOne: {
flex:1,
backgroundColor:"blue"
},
innerTwo: {
flex:4,
backgroundColor:"orange"
}
});
위 예제에서 노란색 영역을 5로 나눈 후, 파랑색 영역이 1/5을, 주황색 영역이 4/5를 가져가는 코드입니다. 상대적! flex는 위치한 곳의 영역을 같은 레발의 flex합 비율대로 가져갑니다!
flexDirection
자리 잡은 영역의 방향입니다.
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
export default function App() {
return (
<View style={styles.container}>
<View style={styles.containerOne}>
</View>
<View style={styles.containerTwo}>
<View style={styles.innerOne}>
</View>
<View style={styles.innerTwo}>
</View>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex:1
},
containerOne: {
flex:1,
backgroundColor:"red"
},
containerTwo:{
flex:2,
flexDirection:"row",
backgroundColor:"yellow"
},
innerOne: {
flex:1,
backgroundColor:"blue"
},
innerTwo: {
flex:4,
backgroundColor:"orange"
}
});
노란색 영역에 넣었던 파랑,주황 영역이 세로에서 가로 방향으로 영역을 다시 잡은 모습을 확인 할 수 있습니다. 즉, row는 가로 방향, column은 세로방향으로 영역을 배치합니다. 기본 값은 column입니다. flex 공부할 때 보면 세로 였죠?
justifyContent
justifyContent는 flexDirection과 동일한 방향으로 정렬하는 속성입니다 flexDirection: 'column'에서 justifyContent는 상하 정렬, flexDirection: 'row'에서 justifyContent는 좌우 정렬을 뜻합니다. flex-start, center, flex-end, space-between, space-around 속성을 가집니다.
space-between 과 space-around
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
export default function App() {
return (
<View style={styles.container}>
<View style={styles.containerOne}>
</View>
<View style={styles.containerTwo}>
<View style={styles.innerOne}>
</View>
<View style={styles.innerTwo}>
<Text>!!컨텐츠!!</Text>
</View>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex:1
},
containerOne: {
flex:1,
backgroundColor:"red"
},
containerTwo:{
flex:2,
flexDirection:"row",
backgroundColor:"yellow"
},
innerOne: {
flex:1,
backgroundColor:"blue"
},
innerTwo: {
flex:4,
justifyContent:"flex-start",
backgroundColor:"orange"
}
});
innerOne,Two를 모두 감싸고 있는 containerTwo의 flexDirection 속성값을 변경하면서, innerTwo의 justifyContent 속성값을 이리저리 변경해보세요! 상위 엘리먼트 영역의 flexDirection을 따라서 컨텐츠 위치도 변경됨을 알 수 있습니다.
alignItems
Align Items는 Flex Direction과 수직한 방향(반대 방향이라고 생각하면 편합니다)으로 정렬하는 속성입니다. flexDirection: 'column'에서 alignItems는 좌우 정렬, flexDirection: 'row'에서 alignItems는 상하 정렬을 뜻합니다 flex-start, center, flex-end, stretch 속성을 가집니다.
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
export default function App() {
return (
<View style={styles.container}>
<View style={styles.containerOne}>
</View> <View style={styles.containerTwo}>
<View style={styles.innerOne}>
</View>
<View style={styles.innerTwo}>
<View style={styles.content}>
</View>
</View>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex:1
},
containerOne: {
flex:1,
backgroundColor:"red"
},
containerTwo:{
flex:2,
flexDirection:"row",
backgroundColor:"yellow"
},
innerOne: {
flex:1,
backgroundColor:"blue"
},
innerTwo: {
flex:4,
backgroundColor:"orange",
alignItems:"flex-end"
},
content: {
width:50,
height:50,
backgroundColor:"#000"
}
});
innerTwo( 상위 엘리먼트 ) 에 적용을 해야 안에 있는 컨텐츠에 영향이 간다!
[앱 화면 만들기] 메인화면 꾸미기
가이드
1) 상단에 '나만의 꿀팁' 제목 텍스트를 넣어야 겠다
2) 제목 바로 밑에 이미지를 해당 이미지를 넣어야 겠다(이미지 제공 해드립니다 🙂)
3) 가운데 버튼은 횡(수평) 스크롤(ScrollView) 기능을 써서 좌우로 스크롤 가능하게 만들어야 겠다
4) ScrollVoew 수직 스크롤은 그냥 쓰면 된다는 것을 알았지만 횡은 어떻게 해야할까?
공식문서를 찾아봐야지, 수평은 영어로 Horizontal
5) 주어진 데이터는 문자이므로 Text 태그에 넣어야 겠다.
6) 설명 글은 긴데 3줄이 넘어가면, 말 줄임표가 되네! Text 태그 속성에 이런 기능이 있는지 공식문서에서 찾아봐야겠다. 7) 피자 이미지와 글자 부분의 영역을 대~충 1 : 3정도로 분할하면 되겠네
-스타일 공식 문서
https://reactnative.dev/docs/style#docsNav
Style · React Native
With React Native, you style your application using JavaScript. All of the core components accept a prop named style. The style names and values usually match how CSS works on the web, except names are written using camel casing, e.g. backgroundColor rathe
reactnative.dev
https://reactnative.dev/docs/layout-props
Layout Props · React Native
More detailed examples about those properties can be found on the Layout with Flexbox page.
reactnative.dev
1) 이미지는 이 이미지를 사용하세요!
- 가장 상단의 큰 메인이미지 : https://firebasestorage.googleapis.com/v0/b/sparta-image.appspot.com/o/lecture%2Fmain.png?alt=media&token=8e5eb78d-19ee-4359-9209-347d125b322c
- 피자 작은 이미지: https://firebasestorage.googleapis.com/v0/b/sparta-image.appspot.com/o/lecture%2Fpizza.png?alt=media&token=1a099927-d818-45d4-b48a-7906fd0d2ad3
2) 꿀팁 데이터를 다음 문자 데이터를 사용해서 Text태그에 적용해보세요
꿀팁 제목: 먹다 남은 피자를 촉촉하게!
꿀팁 설명: 먹다 남은 피자는 수분이 날라가기 때문에 처음처럼 맛있게 먹을 수 없는데요. 이럴 경우 그릇에 물을 받아 전자레인지 안에서 1분 30초에서 2분 정도 함께 돌려주면 촉촉하게 먹을 수 있습니다. 물이 전자레인지 안에서 수증기를 일으키고, 피자에 촉촉함을 더해줍니다.
꿀팁 날짜: 2020.09.09
3) ScrollView 의 스크롤 방향을 공식 문서에서 찾아서 변경해보세요
https://docs.expo.io/versions/v38.0.0/react-native/scrollview/
horizontal 부분을 살펴보세요!
Text 태그가 가지고 있는 속성 중에서 말줄임표 기능이 있는지 찾아보고 적용해보세요
https://reactnative.dev/docs/text?redirected
Text · React Native
A React component for displaying text.
reactnative.dev
가운데 버튼은 총 네가지 입니다.
생활, 재테크, 반려견, 꿀팁 찜 이 네가지 카테고리로 메인 이미지 밑의 버튼들을 만들어주세요!
[앱 화면 만들기] 메인화면 완성
라이브러리 임포트
import React from 'react';
import main from './assets/main.png';
import { StyleSheet, Text, View, Image, TouchableOpacity, ScrollView} from 'react-native';
기본 함수 골격 export default function App( ) { }
export default function App() {
return ()
}
const styles = StyleSheet.create({ })
메인 이미지
피자 이미지
완성 코드보기
import React from 'react';
import { StyleSheet, Text, View, Image, TouchableOpacity, ScrollView} from 'react-native';
export default function App() {
//return 구문 밖에서는 슬래시 두개 방식으로 주석
return ( /* return 구문 안에서는 {슬래시 + * 방식으로 주석 */ 나만의 꿀팁
생활 재테크 반려견 꿀팁 찜 {/* 하나의 카드 영역을 나타내는 View */}
https://firebasestorage.googleapis.com/v0/b/sparta-image.appspot.com/o/lecture%2Fpizza.png?alt=media&token=1a099927-d818-45d4-b48a-7906fd0d2ad3"}}/> 먹다 남은 피자를 촉촉하게! 먹다 남은 피자는 수분이 날라가기 때문에 처음처럼 맛있게 먹을 수 없는데요. 이럴 경우 그릇에 물을 받아 전자레인지 안에서 1분 30초에서 2분 정도 함께 돌려주면 촉촉하게 먹을 수 있습니다. 물이 전자레인지 안에서 수증기를 일으키고, 피자에 촉촉함을 더해줍니다.
2020.09.09
);
}
const styles = StyleSheet.create({
container: {
//앱의 배경 색
backgroundColor: '#fff',
},
title: { //폰트 사이즈 fontSize: 20,
//폰트 두께 fontWeight: '700', //위 공간으로 부터 이격 marginTop:50,
//왼쪽 공간으로 부터 이격' marginLeft:20 },
mainImage: {
//컨텐츠의 넓이 값 width:'90%',
//컨텐츠의 높이 값 height:200,
//컨텐츠의 모서리 구부리기 borderRadius:10, marginTop:20,
//컨텐츠 자체가 앱에서 어떤 곳에 위치시킬지 결정(정렬기능)
//각 속성의 값들은 공식문서에 고대로~ 나와 있음
alignSelf:"center"
},
middleContainer:{
marginTop:20,
marginLeft:10,
height:60
},
middleButton01: {
width:100,
height:50,
padding:15,
backgroundColor:"#fdc453",
borderColor:"deeppink",
borderRadius:15,
margin:7
},
middleButton02: {
width:100,
height:50,
padding:15,
backgroundColor:"#fe8d6f",
borderRadius:15,
margin:7
},
middleButton03: {
width:100,
height:50,
padding:15,
backgroundColor:"#9adbc5",
borderRadius:15,
margin:7
},
middleButton04: {
width:100,
height:50,
padding:15,
backgroundColor:"#f886a8",
borderRadius:15,
margin:7
},
middleButtonText: {
color:"#fff",
fontWeight:"700",
//텍스트의 현재 위치에서의 정렬
textAlign:"center"
},
cardContainer: {
marginTop:10,
marginLeft:10
},
card:{
flex:1,
//컨텐츠들을 가로로 나열
//세로로 나열은 column <- 디폴트 값임
flexDirection:"row",
margin:10,
borderBottomWidth:0.5,
borderBottomColor:"#eee",
paddingBottom:10
},
cardImage: {
flex:1,
width:100,
height:100,
borderRadius:10,
},
cardText: {
flex:2,
flexDirection:"column",
marginLeft:10,
},
cardTitle: {
fontSize:20,
fontWeight:"700"
},
cardDesc: {
fontSize:15
},
cardDate: {
fontSize:10,
color:"#A6A6A6",
}
});
13.[앱&자바스크립트] 모듈과 반복문
모듈 시스템(module system)
//A.js 파일
//times, plusTwo 함수를 외부로 내보낼 준비를 합니다.
export function times(x) {
return x * x;
}
export function plusTwo(number) {
return number + 2;
}
//B.js 파일
//다른 자바스크립트 파일에서 다음과 같이 불러와 사용합니다.
import { times, plusTwo } from './util.js';
console.log(times(2));
console.log(plusTwo(3));
앱에서의 모듈 시스템
1) 간단히는 App.js는 앱의 화면을 그려주는 커다란 함수입니다. 또는!
2) 자세히는 App.js는 리액트 네이티브 라이브러리 그리고 Expo에서 제공해주는 기능들을 사용하여 화면을 그려주는 커다란 함수입니다.
그리고 App.js는 모듈 시스템에 의해 내보내지고 있습니다.
export default function App() { ... }
즉, 화면을 그리는 함수(여기선 App()을 가르킵니다)가 내보내져서 어디선가 사용이 되며, 사용이 되는 것 즉 화면을 그리게 된다는 뜻입니다. 간단히 정리해보면, 우리가 만든 화면을 그리는 함수들은 리액트 네이티브로 전달되어(내보내져서 == export) 화면을 최종적으로 그린다는 것으로 이해하면 충분합니다. 그래서 앞으로도 여러 앱 파일을 만들때, export default function 으로 함수를 내보낼 계획입니다
모듈 시스템으로 data.json을 불러오기
모듈 시스템은, 화면을 그리는 함수 말고도 데이터를 다룰 때도 유용하게 사용됩니다. 다음은 열심히 모아본 꿀팁 10가지 입니다. 딕셔너리 + 리트스 복합 구조로, JSON 데이터 형식으로 준비해 봤습니다. 해당 코드를 프로젝트에 data.json 파일을 만든 다음 복붙해서 넣어주세요
data.json
{
"tip":[
{ "idx":0, "category":"생활",
"title":"먹다 남은 피자를 촉촉하게!",
"desc":"먹다 남은 피자는 수분이 날라가기 때문에 처음처럼 맛있게 먹을 수 없는데요. 이럴 경우 그릇에 물을 받아 전자레인지 안에서 1분 30초에서 2분 정도 함께 돌려주면 촉촉하게 먹을 수 있습니다. 물이 전자레인지 안에서 수증기를 일으키고, 피자에 촉촉함을 더해줍니다.",
"date":"2020.09.09"
},
{ "idx":1,
"category":"생활",
"title":"바나나를 싱싱하게 보관하기",
"desc":"바나나에 날파리가 꼬이거나 금방 익어버리는 것을 예방하기 위한 방법인데요. 바나나 양쪽 끝을 자른 후, 보관용 케이스나 비닐봉지에 묶어 밀봉합니다. 그리고 냉장고에 넣어주면 되는데요. 하루에 1~2개씩 꺼내서 싱싱하게 먹을 수 있습니다.",
"date":"2020.09.09"
},
{
"idx":2,
"category":"생활",
"title":"셔츠에 묻은 볼펜 자국 없애기",
"image": "https://firebasestorage.googleapis.com/v0/b/sparta-image.appspot.com/o/lecture%2Fshirt.png?alt=media&token=6388d9fb-f87f-4234-b580-46a2f918aab1", "desc":"셔츠를 자주 입는 사람의 경우, 종종 볼펜 자국이 묻기 마련인데요. 이럴 경우에는 집에 있는 물파스로 가볍게 지울 수 있습니다. 옷 뒷부분을 키친타올로 받쳐 번지는 것을 방지한 후, 볼펜 자국 있는 부분을 물파스로 눌러주고, 키친타올로 닦아냅니다.", "date":"2020.09.09" }, { "idx":3, "category":"재테크", "title":"잠자는 내 돈을 찾아라", "image": "https://firebasestorage.googleapis.com/v0/b/sparta-image.appspot.com/o/lecture%2Fmoney1.png?alt=media&token=491096e7-0b57-40a3-991b-b984193f8018", "desc":"‘새는 돈’에는 미처 몰랐던 카드 포인트, 휴면예금이나 환급금도 포함됩니다. 확실히 파악하지 못한 잠자는 돈을 찾아보고 자투리 돈들을 모으는 것도 중요합니다. 케이블방송, 위성방송 서비스를 이용하면서 중복 납부한 요금, 셋톱박스 보증금 등 돌려받지 않은 돈이 있는지 확인 해보세요. 또, 카드 포인트 통합 조회 서비스를 이용해 여러 개의 카드 포인트가 모두 얼마인지 체크해두는 것이 좋습니다. 보험해약 환급금, 휴면 보험금이나 휴면 예금을 찾아보고 돌려받는 일도 요즘에는 어렵지 않습니다.", "date":"2020.09.09" }, { "idx":4, "category":"재테크", "title":"할인행사, 한정할인판매 문구의 함정 탈출!", "image": "https://firebasestorage.googleapis.com/v0/b/sparta-image.appspot.com/o/lecture%2Fmoney2.png?alt=media&token=9c9df304-16e8-4a6f-8ae4-1d3f9ad58134", "desc":"‘안 사면 100% 할인’이라는 말 들어보셨나요? 견물생심, 좋은 물건을 보면 사고 싶기 마련입니다. 특히 대대적인 ‘할인 행사’ 중인 대형 마트에 갔을 때는 말할 것도 없겠죠. 따라서 생필품을 살 때, 한꺼번에 사서 사용하는 것보다 필요할 때 조금씩 구매하는 편이 좋습니다. 장을 보면서 대형마트에 자주 가다 보면 지금 필요한 것뿐 아니라 앞으로 필요할 것까지 사게 되어 지출이 커지기 때문입니다. 특히 할인 품목을 보면 뜻하지 않은 소비를 하는 경우도 많아진다. 홈쇼핑, 대형마트 등의 ‘할인행사’, ‘한정할인판매’ 등의 문구를 조심하세요. ", "date":"2020.09.09" }, { "idx":5, "category":"생활", "title":"방전된 건전지 살리기", "image": "https://firebasestorage.googleapis.com/v0/b/sparta-image.appspot.com/o/lecture%2Fbattery.png?alt=media&token=7b2f37a2-537d-4b98-a139-da6aa2f420ec", "desc":"건전지를 다 사용하지 않아도 방전되면, 버리는 경우가 종종 있는데요. 건전지의 무게감이 느껴진다면, 드라이기를 활용해 방전된 건전지를 깨울 수 있습니다. 드라이기 열기를 10초~30초 정도 골고루 가해주면 되는데요. 건전지가 불필요하게 낭비되는 것을 막을 수 있습니다.", "date":"2020.09.09" }, { "idx":6, "category":"반려견", "title":"반려견에게 배변 교육 시킬 때", "image": "https://firebasestorage.googleapis.com/v0/b/sparta-image.appspot.com/o/lecture%2Fpuppy.png?alt=media&token=85ba2c18-d263-4857-8e09-8922cc14ad29", "desc":"우선, 배변패드를 순서대로 돌며 간식을 조금씩 떨어뜨려 놓는다. 2단계는 배변패드 앞에서 기다렸다 반려견이 스스로 올라오면 간식을 주어서 보상하고, 3단계는 “화장실 가자”나 “매트” 같은 명령어를 붙여 말한 뒤 배변패드에 올라오면 간식을 주는 것이다. 마지막 단계는 배변패드에 올라간 반려견이 대소변을 본 다음 간식을 줌으로써 이 장소가 즐거운 곳이라는 인식을 심어주는 것이다. 그리고 무엇보다 1, 2회 사용한 배변패드는 바로 갈아줘야 한다.", "date":"2020.09.09" }, { "idx":7, "category":"반려견", "title":"반려견이 주인과 떨어지는 것을 무서워 할 때", "image": "https://firebasestorage.googleapis.com/v0/b/sparta-image.appspot.com/o/lecture%2Fpuppy2.png?alt=media&token=3f07ca26-6791-4d9a-8638-264f80c01038", "desc":"분리불안교육은 반려견에게 혼자 남는 법을 알려주기 위한 것이 아니라, 보호자가 ‘언제나 너에게 돌아올 거야’라고 알려주는 교육이다. 반려견과 5초 동안 떨어져 있다가 다시 문을 열고 들어가 손 냄새를 맡게 해주는 훈련을 하루 10번씩 7일 동안 반복하는 ‘5,10,7 법칙’을 통해 반려견의 마음을 편안하게 해줄 수 있다.", "date":"2020.09.09" }, { "idx":8, "category":"반려견", "title":"반려견을 아이와 함께 키울 때", "image": "https://firebasestorage.googleapis.com/v0/b/sparta-image.appspot.com/o/lecture%2Fpuppy3.png?alt=media&token=b59fa6d7-7d3d-4147-8401-88bba030ec25", "desc":"‘인간의 행복’을 위해 반려동물을 키우는 것에 대해 꾸준히 비판과 우려를 제기해온 그는 특히 ‘아이들의 정서’를 위해 반려견을 키우려 한다는 부모들에게 당부한다. “반려동물을 통해 아이들의 정서가 좋아진다면, 그것은 부모가 나와 생김새와 느낌, 말과 행동이 다른 동물을 아끼는 모습을 보기 때문입니다.” 인간의 뜻에 의해 인간과 함께 살게 된 생명을 좀 더 이해하고 행복하게 살 수 있도록 하는 것은 역시 인간의 노력에 달려 있다.", "date":"2020.09.09" }, { "idx":9, "category":"재테크", "title":"렌탈 서비스 금액 비교해보기", "image": "https://firebasestorage.googleapis.com/v0/b/sparta-image.appspot.com/o/lecture%2Frental.png?alt=media&token=97a55844-f077-4aeb-8402-e0a27221570b", "desc":"요즘은 정수기, 공기 청정기, 자동차나 장난감 등 다양한 대여서비스가 활발합니다. 사는 것보다 경제적이라고 생각해 렌탈 서비스를 이용하는 분들이 늘어나고 있는데요. 다만, 이런 렌탈 서비스 이용이 하나둘 늘어나다 보면 그 금액은 겉잡을 수 없이 불어나게 됩니다. 특히, 렌탈 서비스는 빌려주는 물건의 관리비용까지 포함된 것이기에 생각만큼 저렴하지 않습니다. 직접 관리하며 사용할 수 있는 물건이 있는지 살펴보고, 렌탈 서비스 항목에서 제외해보세요. 렌탈 비용과 구매 비용, 관리 비용을 여러모로 비교해보고 고민해보는 것이 좋습니다. ", "date":"2020.09.09" } ] }
이렇게 파일을 준비한다음, 반복문 다루기에서 해당 data.json 파일안에 담겨있는 데이터를 사용해보도록 하겠습니다
데이터를 반복문 돌려보기
준비한 데이터를 자바스크립트 App.js 파일에서 불러올 땐, 상단에서 다음과 같이 불러오면 됩니다.
import data from './data.json';
./ ⇒ 현재 파일과 동일한 위치에서 불러올 파일을 찾는 코드
../ ⇒ 현재 파일이 위치한 폴더보다 상위 위치에서 불러올 파일을 찾는 코드 강의 초반에 cd .. 에 대해 다루었었죠?
..은 현재 위치한 폴더 뒤로가는 코드 였습니다 이렇게 어디에 위치한 파일인지 명시하고 불러온다음, data라는 이름으로 불러왔스니다.
파일 자체를 App.js로 불러오는 것이기 때문에, 원하는 변수명으로 불러올 수 있습니다.
data.json 반복 적용 모습
map을 이용한 JSX 안에서 반복 적용
한 줄 문법, map 같은 자바스크립트 문법은 {} 안에서 사용할 수 있습니다. 따라서 다음과 같이 간단히 반복문을 JSX 문법 안에서 구현 할 수도 있습니다.
App.js JSX 문법 안에서 map을 이용한 반복문
import React from 'react';
import { StyleSheet, Text, View, Image, TouchableOpacity, ScrollView} from 'react-native';
import data from './data.json';
export default function App() {
let tip = data.tip;
let todayWeather = 10 + 17;
let todayCondition = "흐림"
//return 구문 밖에서는 슬래시 두개 방식으로 주석
return (
/*
return 구문 안에서는 {슬래시 + * 방식으로 주석
*/
<ScrollView style={styles.container}>
<Text style={styles.title}>나만의 꿀팁</Text>
<Image style={styles.mainImage} source={{uri:main}}/>
<ScrollView style={styles.middleContainer} horizontal indicatorStyle={"white"}>
<TouchableOpacity style={styles.middleButton01}><Text style={styles.middleButtonText}>생활</Text> </TouchableOpacity>
<TouchableOpacity style={styles.middleButton02}><Text style={styles.middleButtonText}>재테크</Text> </TouchableOpacity>
<TouchableOpacity style={styles.middleButton03}><Text style={styles.middleButtonText}>반려견</Text> </TouchableOpacity>
<TouchableOpacity style={styles.middleButton04}><Text style={styles.middleButtonText}>꿀팁 찜</Text> </TouchableOpacity>
</ScrollView>
<View style={styles.cardContainer}>
{/* 하나의 카드 영역을 나타내는 View */}
tip.map((content,i)=>{
return (
<View style={styles.card} key={i}>
<Image style={styles.cardImage} source={{uri:content.image}}/>
<View style={styles.cardText}>
<Text style={styles.cardTitle} numberOfLines={1}>{content.title}</Text>
<Text style={styles.cardDesc} numberOfLines={3}>{content.desc}</Text>
<Text style={styles.cardDate}>{content.date}</Text>
</View>
</View>)
})
}
</View>
</ScrollView>
);
}
const styles = StyleSheet.create({
//앱의 배경 색
backgroundColor: '#fff',
},
title: {
//폰트 사이즈
fontSize: 20,
//폰트 두께
fontWeight: '700',
//위 공간으로 부터 이격
marginTop:50,
//왼쪽 공간으로 부터 이격
marginLeft:20
},
weather:{
alignSelf:"flex-end",
paddingRight:20
},
mainImage: {
//컨텐츠의 넓이 값
width:'90%',
//컨텐츠의 높이 값
height:200,
//컨텐츠의 모서리 구부리기
borderRadius:10,
marginTop:20,
//컨텐츠 자체가 앱에서 어떤 곳에 위치시킬지 결정(정렬기능)
//각 속성의 값들은 공식문서에 고대로~ 나와 있음
alignSelf:"center"
},
middleContainer:{
marginTop:20,
marginLeft:10,
height:60
},
middleButton01: {
width:100,
height:50,
padding:15,
backgroundColor:"#fdc453",
borderColor:"deeppink",
borderRadius:15,
margin:7
},
middleButton02: {
width:100,
height:50,
padding:15,
backgroundColor:"#fe8d6f",
borderRadius:15,
margin:7
},
middleButton03: {
width:100,
height:50,
padding:15,
backgroundColor:"#9adbc5",
borderRadius:15,
margin:7
},
middleButtonText: {
color:"#fff",
fontWeight:"700",
//텍스트의 현재 위치에서의 정렬
textAlign:"center"
},
middleButton04: {
width:100,
height:50,
padding:15,
backgroundColor:"#f886a8",
borderRadius:15,
margin:7
},
cardContainer: {
marginTop:10,
marginLeft:10
},
card:{
flex:1,
//컨텐츠들을 가로로 나열
//세로로 나열은 column <- 디폴트 값임
flexDirection:"row",
margin:10,
borderBottomWidth:0.5,
borderBottomColor:"#eee",
paddingBottom:10
},
cardImage: {
flex:1,
width:100,
height:100,
borderRadius:10,
},
cardText: {
flex:2,
flexDirection:"column",
marginLeft:10,
},
cardTitle: {
fontSize:20,
fontWeight:"700"
},
cardDesc: {
fontSize:15
},
cardDate: {
fontSize:10,
color:"#A6A6A6",
},
});
14. [앱&자바스크립트] {} 표현식과 조건문
화면을 조건문으로 달리 표현해보기
홀수 팁만 노란색 바탕화면 적용 모습
'이것' 아니면 '저것'과 같이 단순하게 선택사항이 두 가지 뿐이라면 if, else 구문은 다소 코드가 길어지는 감이 있을겁니다. 이럴때 아주 짧게 쓸 수 있는 자바스크립트 문법이 있어요! 바로 삼항 연산자 입니다. 리엑트 네이티브로 앱을 만들 때 가장 많이 사용되는 조건문입니다. 다음 코드를 보시죠!
let result = 10 > 2 ? "참" : "거짓"
(기본 모습)
let result = 조건 ? 참일 때 : 거짓 일때
(예제)
let result = 10 == 9 ? true : false // result <-- false 값 할당
let result = 10 !== 9 ? true : false // result <-- true 값 할당
let reuslt = 99 > 10 ? true : false // result <-- true 값 할당
10은 2보다 큰가요 작은가요? 당연히 크죠? 그럴땐 ? 물음표 뒤의 값이 result에 담겨지게 됩니다. 만약 앞의 10 > 2 부분의 조건이 거짓이게 된다면, : 콜론 뒤에 있는 값이 result에 담기게 되요!
{} 표현식 안에서 조건문 사용: 삼항 연산자
import React from 'react';
import { StyleSheet, Text, View, Image, TouchableOpacity, ScrollView} from 'react-native';
import data from './data.json';
export default function App() {
let tip = data.tip;
let todayWeather = 10 + 17;
let todayCondition = "흐림" //return 구문 밖에서는 슬래시 두개 방식으로 주석
return (
/* return 구문 안에서는 {슬래시 + * 방식으로 주석 */
<ScrollView style={styles.container}> <Text style={styles.title}>나만의 꿀팁</Text> <Text style={styles.weather}>오늘의 날씨: {todayWeather + '°C ' + todayCondition} </Text> <Image style={styles.mainImage} source={{uri:main}}/> <ScrollView style={styles.middleContainer} horizontal indicatorStyle={"white"}> <TouchableOpacity style={styles.middleButton01}><Text style={styles.middleButtonText}>생활</Text></TouchableOpacity> <TouchableOpacity style={styles.middleButton02}><Text style={styles.middleButtonText}>재테크</Text></TouchableOpacity> <TouchableOpacity style={styles.middleButton03}><Text style={styles.middleButtonText}>반려견</Text></TouchableOpacity> <TouchableOpacity style={styles.middleButton04}><Text style={styles.middleButtonText}>꿀팁 찜</Text></TouchableOpacity> </ScrollView> <View style={styles.cardContainer}> {/* 하나의 카드 영역을 나타내는 View */} { tip.map((content,i)=>{ return i % 2 == 0 ? (<View style={styles.cardEven} key={i}> <Image style={styles.cardImage} source={{uri:content.image}}/> <View style={styles.cardText}> <Text style={styles.cardTitle} numberOfLines={1}>{content.title}</Text> <Text style={styles.cardDesc} numberOfLines={3}>{content.desc}</Text> <Text style={styles.cardDate}>{content.date}</Text> </View> </View>) : (<View style={styles.cardOdd} key={i}> <Image style={styles.cardImage} source={{uri:content.image}}/> <View style={styles.cardText}> <Text style={styles.cardTitle} numberOfLines={1}>{content.title}</Text> <Text style={styles.cardDesc} numberOfLines={3}>{content.desc}</Text> <Text style={styles.cardDate}>{content.date}</Text> </View> </View>) }) } </View> </ScrollView> ); }
const styles = StyleSheet.create({
container: {
//앱의 배경 색
backgroundColor: '#fff',
},
title: {
//폰트 사이즈
fontSize: 20,
//폰트 두께
fontWeight: '700',
//위 공간으로 부터 이격
marginTop:50,
//왼쪽 공간으로 부터 이격
marginLeft:20
},
weather:{
alignSelf:"flex-end",
paddingRight:20
},
mainImage: {
//컨텐츠의 넓이 값 width:'90%',
//컨텐츠의 높이 값 height:200,
//컨텐츠의 모서리 구부리기 borderRadius:10, marginTop:20,
//컨텐츠 자체가 앱에서 어떤 곳에 위치시킬지 결정(정렬기능)
//각 속성의 값들은 공식문서에 고대로~ 나와 있음 alignSelf:"center" }, middleContainer:{ marginTop:20, marginLeft:10, height:60
},
middleButton01: {
width:100,
height:50,
padding:15,
backgroundColor:"#fdc453",
borderColor:"deeppink",
borderRadius:15, margin:7
},
middleButton02: {
width:100,
height:50,
padding:15,
backgroundColor:"#fe8d6f",
borderRadius:15,
margin:7
},
middleButton03: {
width:100,
height:50,
padding:15,
backgroundColor:"#9adbc5",
borderRadius:15,
margin:7
},
middleButtonText: {
color:"#fff",
fontWeight:"700",
//텍스트의 현재 위치에서의 정렬
textAlign:"center"
},
middleButton04: {
width:100,
height:50,
padding:15,
backgroundColor:"#f886a8",
borderRadius:15,
margin:7
},
cardContainer: {
marginTop:10,
marginLeft:10
},
card:{
flex:1,
//컨텐츠들을 가로로 나열
//세로로 나열은 column <- 디폴트 값임
flexDirection:"row",
margin:10,
borderBottomWidth:0.5,
borderBottomColor:"#eee",
paddingBottom:10
},
cardImage: {
flex:1,
width:100,
height:100,
borderRadius:10,
},
cardText: {
flex:2,
flexDirection:"
column",
marginLeft:10,
},
cardTitle: {
fontSize:20,
fontWeight:"700"
},
cardDesc: {
fontSize:15 },
cardDate: {
fontSize:10,
color:"#A6A6A6",
},
cardEven:{
flex:1,
flexDirection:"row",
margin:10,
backgroundColor:"#FFFED7",
borderRadius:20,
borderBottomWidth:0.5,
borderBottomColor:"#eee",
paddingBottom:10
},
cardOdd:{
flex:1,
flexDirection:"row",
margin:10,
borderBottomWidth:0.5,
borderBottomColor:"#eee",
paddingBottom:10
},
});
조건문 공부 후 원래대로 돌리기!
import React from 'react'; import { StyleSheet, Text, View, Image, TouchableOpacity, ScrollView} from 'react-native'; const main = 'https://firebasestorage.googleapis.com/v0/b/sparta-image.appspot.com/o/lecture%2Fmain.png?alt=media&token=8e5eb78d-19ee-4359-9209-347d125b322c' import data from './data.json'; export default function App() { let tip = data.tip; let todayWeather = 10 + 17; let todayCondition = "흐림" //return 구문 밖에서는 슬래시 두개 방식으로 주석 return ( /* return 구문 안에서는 {슬래시 + * 방식으로 주석 */
<ScrollView style={styles.container}> <Text style={styles.title}>나만의 꿀팁</Text> <Text style={styles.weather}>오늘의 날씨: {todayWeather + '°C ' + todayCondition} </Text> <Image style={styles.mainImage} source={{uri:main}}/> <ScrollView style={styles.middleContainer} horizontal indicatorStyle={"white"}> <TouchableOpacity style={styles.middleButton01}><Text style={styles.middleButtonText}>생활</Text></TouchableOpacity> <TouchableOpacity style={styles.middleButton02}><Text style={styles.middleButtonText}>재테크</Text></TouchableOpacity> <TouchableOpacity style={styles.middleButton03}><Text style={styles.middleButtonText}>반려견</Text></TouchableOpacity> <TouchableOpacity style={styles.middleButton04}><Text style={styles.middleButtonText}>꿀팁 찜</Text></TouchableOpacity> </ScrollView> <View style={styles.cardContainer}> {/* 하나의 카드 영역을 나타내는 View */} { tip.map((content,i)=>{ return (<View style={styles.card} key={i}> <Image style={styles.cardImage} source={{uri:content.image}}/> <View style={styles.cardText}> <Text style={styles.cardTitle} numberOfLines={1}>{content.title}</Text> <Text style={styles.cardDesc} numberOfLines={3}>{content.desc}</Text> <Text style={styles.cardDate}>{content.date}</Text> </View> </View>) }) } </View> </ScrollView> ); }
const styles = StyleSheet.create({ container: { //앱의 배경 색 backgroundColor: '#fff', }, title: { //폰트 사이즈 fontSize: 20, //폰트 두께 fontWeight: '700', //위 공간으로 부터 이격 marginTop:50, //왼쪽 공간으로 부터 이격 marginLeft:20 }, weather:{ alignSelf:"flex-end", paddingRight:20 }, mainImage: { //컨텐츠의 넓이 값 width:'90%', //컨텐츠의 높이 값 height:200, //컨텐츠의 모서리 구부리기 borderRadius:10, marginTop:20, //컨텐츠 자체가 앱에서 어떤 곳에 위치시킬지 결정(정렬기능) //각 속성의 값들은 공식문서에 고대로~ 나와 있음 alignSelf:"center" }, middleContainer:{ marginTop:20, marginLeft:10, height:60 }, middleButton01: { width:100, height:50, padding:15, backgroundColor:"#fdc453", borderColor:"deeppink", borderRadius:15, margin:7 }, middleButton02: { width:100, height:50, padding:15, backgroundColor:"#fe8d6f", borderRadius:15, margin:7 }, middleButton03: { width:100, height:50, padding:15, backgroundColor:"#9adbc5", borderRadius:15, margin:7 }, middleButtonText: { color:"#fff", fontWeight:"700", //텍스트의 현재 위치에서의 정렬 textAlign:"center" }, middleButton04: { width:100, height:50, padding:15, backgroundColor:"#f886a8", borderRadius:15, margin:7 }, cardContainer: { marginTop:10, marginLeft:10 }, card:{ flex:1, //컨텐츠들을 가로로 나열 //세로로 나열은 column <- 디폴트 값임 flexDirection:"row", margin:10, borderBottomWidth:0.5, borderBottomColor:"#eee", paddingBottom:10 }, cardImage: { flex:1, width:100, height:100, borderRadius:10, }, cardText: { flex:2, flexDirection:"column", marginLeft:10, }, cardTitle: { fontSize:20, fontWeight:"700" }, cardDesc: { fontSize:15 }, cardDate: { fontSize:10, color:"#A6A6A6", },
});
2주차 끝 & 숙제 설명
어바웃 화면 만들기
사용 이미지
1) pages 폴더만들기
2) pages 폴더에 MainPage.js와 AboutPage.js 파일을 만들기
3) App.js 파일 코드 모두 복사한 후, MainPage.js에 붙여넣기 한 다음 함수 이름을 MainPage 로 바꿔주세요
4) 그리고 MainPage.js의 코드 줄은 다음과 같이 변경해주세요
import data from './data.json';
에서
import data from '../data.json';
5) App.js 코드는 다음 코드로 변경해주세요
import React from 'react'
import MainPage from './pages/MainPage';
export default function App(){
return (<MainPage/>) }
우리가 배운 import, export를 개념을 통해서말이죠! 그럼 AboutPage 즉, 소개 페이지를 보려면 어떻게 해야할까요? 일단은 App.js return에서 내보내어 화면을 그리고 있는 MainPage를 주석치고 상단에서 AboutPage를 불러온 다음 주석친 MainPage 대신 넣어줘야 합니다.
6) AboutPage를 return에 담기
import React from 'react'
import MainPage from './pages/MainPage';
import AboutPage from './pages/AboutPage';
export default function App(){
// return (<MainPage/>)
return (<AboutPage/>) }
7) AboutPage.js 코드 시작 준비!
import React from 'react'
import {View,Text} from 'react-native'
export default function AboutPage(){
return (
<View>
<Text>어바웃페이지</Text>
</View>) }
수강과정에서 어려운점:
1.한번 에러가 발생하면 expo간 반응하지 않을때.먹통이 될때가 많음.
그럴때마다 PC를 재부팅하는 방법으로 해결.
expo 소프트가 아직도 많은 개선이 필요하듯.
2.안드로이드에 시뮬레이터 설치하는 과정에서 4시간을 허비했음.
따라하면 그만이라고 생각했는데 에러가 발생하여 해결하는데 4시간 소요.
3.숙제는 반정도 밖에 못해서 그냥 숙제 해설을 보고 보충해 넣었음.
쉬울것같으면서도 어려운 점.