#3주차_2
페이지 이동하기
MainPage.js에서 카드버튼을 누르면 Card.js 꿀팁 상세 페이지 DetailPage.js로 이동
Stack.screen에 등록된 모든 페이지 컴포넌트들은 navigation과 route라는 딕셔너리(객체)를 속성으로 넘겨받아 사용할 수 있다.
//navigation 객체가 가지고 있는 두 함수(setOptions와 navigate)
//해당 페이지의 제목을 설정할 수 있음
navigation.setOptions({
title:'나만의 꿀팁'
})
//Stack.screen에서 name 속성으로 정해준 이름을 지정해주면 해당 페이지로 이동하는 함수
navigation.navigate("DetailPage")
//name 속성을 전달해주고, 두 번째 인자로 딕셔너리 데이터를 전달해주면, Detail 페이지에서
//두번째 인자로 전달된 딕셔너리 데이터를 route 딕셔너리로 로 받을 수 있음
navigation.navigate("DetailPage",{
title: title
})
//전달받은 데이터를 받는 route 딕셔너리
//비구조 할당 방식으로 route에 params 객체 키로 연결되어 전달되는 데이터를 꺼내 사용
//navigate 함수로 전달되는 딕셔너리 데이터는 다음과 같은 모습이기 때문입니다.
/*
{
route : {
params :{
title:title
}
}
}
*/
const { title} = route.params;
- 비구조할당방식
title에 데이터 할당 : route.params
navigate(“”,{title:title[route.params지정]})
1.MainPage.js
import React,{useState,useEffect} from 'react';
import { StyleSheet, Text, View, Image, TouchableOpacity, ScrollView} from 'react-native';
const main = 'https://storage.googleapis.com/sparta-image.appspot.com/lecture/main.png'
import data from '../data.json';
import Card from '../components/Card';
import Loading from '../components/Loading';
import { StatusBar } from 'expo-status-bar';
/*
MainPage()
MainPage({navigation,route})
-StackNavigator.js 에서 <Stack.Screen name="MainPage" component={MainPage}/> 식으로 정의해서 할당한다.
: Stack.Screen 에서 컴포넌트화 되면서 navigation 과 route를 사용할 수 있게 된다.
MainPage안에서 비구조 할당방식으로 navigation 과 route를 바로 받아서 사용할 수 있다.
MainPage({navigation,route})
*/
export default function MainPage({navigation,route}) {
//useState 사용법
//[state,setState] 에서 state는 이 컴포넌트에서 관리될 상태 데이터를 담고 있는 변수
//setState는 state를 변경시킬때 사용해야하는 함수
//모두 다 useState가 선물해줌
//useState()안에 전달되는 값은 state 초기값
const [state,setState] = useState([])
const [cateState,setCateState] = useState([])
//하단의 return 문이 실행되어 화면이 그려진다음 실행되는 useEffect 함수
//화면실행 후 가장 먼저 실행될 코드를 정의한다.
//내부에서 data.json으로 부터 가져온 데이터를 state 상태에 담고 있음
const [ready,setReady] = useState(true)
useEffect(()=>{
//뒤의 1000 숫자는 1초를 뜻함
//1초 뒤에 실행되는 코드들이 담겨 있는 함수
setTimeout(()=>{
//헤더의 타이틀 변경
navigation.setOptions({
title:'나만의 꿀팁'
})
setState(data.tip)
setCateState(data.tip)
setReady(false)
},1000)
},[])
const category = (cate) => {
if(cate == "전체보기"){
//전체보기면 원래 꿀팁 데이터를 담고 있는 상태값으로 다시 초기화
setCateState(state)
}else{
setCateState(state.filter((d)=>{
return d.category == cate
}))
}
}
//data.json 데이터는 state에 담기므로 상태에서 꺼내옴
// let tip = state.tip;
let todayWeather = 10 + 17;
let todayCondition = "흐림"
//return 구문 밖에서는 슬래시 두개 방식으로 주석
return ready ? <Loading/> : (
/*
return 구문 안에서는 {슬래시 + * 방식으로 주석
*/
<ScrollView style={styles.container}>
<StatusBar style="light" />
{/* <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.middleButtonAll} onPress={()=>{category('전체보기')}}><Text style={styles.middleButtonTextAll}>전체보기</Text></TouchableOpacity>
<TouchableOpacity style={styles.middleButton01} onPress={()=>{category('생활')}}><Text style={styles.middleButtonText}>생활</Text></TouchableOpacity>
<TouchableOpacity style={styles.middleButton02} onPress={()=>{category('재테크')}}><Text style={styles.middleButtonText}>재테크</Text></TouchableOpacity>
<TouchableOpacity style={styles.middleButton03} onPress={()=>{category('반려견')}}><Text style={styles.middleButtonText}>반려견</Text></TouchableOpacity>
<TouchableOpacity style={styles.middleButton04} onPress={()=>{category('꿀팁 찜')}}><Text style={styles.middleButtonText}>꿀팁 찜</Text></TouchableOpacity>
</ScrollView>
<View style={styles.cardContainer}>
{/* 하나의 카드 영역을 나타내는 View */}
{
cateState.map((content,i)=>{
return (<Card content={content} key={i} navigation={navigation}/>)
})
}
</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
},
middleButtonAll: {
width:100,
height:50,
padding:15,
backgroundColor:"#20b2aa",
borderColor:"deeppink",
borderRadius:15,
margin:7
},
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"
},
middleButtonTextAll: {
color:"#fff",
fontWeight:"700",
//텍스트의 현재 위치에서의 정렬
textAlign:"center"
},
cardContainer: {
marginTop:10,
marginLeft:10
},
});
2.Card.js
import React from 'react';
import {View, Image, Text, StyleSheet,TouchableOpacity} from 'react-native'
//MainPage로 부터 navigation 속성을 전달받아 Card 컴포넌트 안에서 사용
export default function Card({content,navigation}){
return(
//카드 자체가 버튼역할로써 누르게되면 상세페이지로 넘어가게끔 TouchableOpacity를 사용
<TouchableOpacity style={styles.card} onPress={()=>{navigation.navigate('DetailPage')}}>
<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>
</TouchableOpacity>
)
}
const styles = StyleSheet.create({
card:{
flex:1,
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",
}
});
3.DetailPage.js
import React,{useState,useEffect} from 'react';
import { StyleSheet, Text, View, Image, ScrollView,TouchableOpacity,Alert } from 'react-native';
export default function DetailPage({navigation,route}) {
//초기 컴포넌트의 상태값을 설정
//state, setState 뿐 아니라 이름을 마음대로 지정할 수 있음!
const [tip, setTip] = useState({
"idx":9,
"category":"재테크",
"title":"렌탈 서비스 금액 비교해보기",
"image": "https://storage.googleapis.com/sparta-image.appspot.com/lecture/money1.png",
"desc":"요즘은 정수기, 공기 청정기, 자동차나 장난감 등 다양한 대여서비스가 활발합니다. 사는 것보다 경제적이라고 생각해 렌탈 서비스를 이용하는 분들이 늘어나고 있는데요. 다만, 이런 렌탈 서비스 이용이 하나둘 늘어나다 보면 그 금액은 겉잡을 수 없이 불어나게 됩니다. 특히, 렌탈 서비스는 빌려주는 물건의 관리비용까지 포함된 것이기에 생각만큼 저렴하지 않습니다. 직접 관리하며 사용할 수 있는 물건이 있는지 살펴보고, 렌탈 서비스 항목에서 제외해보세요. 렌탈 비용과 구매 비용, 관리 비용을 여러모로 비교해보고 고민해보는 것이 좋습니다. ",
"date":"2020.09.09"
})
useEffect(()=>{
console.log(route)
//Card.js에서 navigation.navigate 함수를 쓸때 두번째 인자로 content를 넘겨줬죠?
//content는 딕셔너리 그 자체였으므로 route.params에 고대~로 남겨옵니다.
//즉, route.params 는 content죠!
navigation.setOptions({
//setOptions로 페이지 타이틀도 지정 가능하고
title:route.params.title,
//StackNavigator에서 작성했던 옵션을 다시 수정할 수도 있습니다.
headerStyle: {
backgroundColor: '#000',
shadowColor: "#000",
},
headerTintColor: "#fff",
})
setTip(route.params)
},[])
const popup = () => {
Alert.alert("팝업!!")
}
return (
// ScrollView에서의 flex 숫자는 의미가 없습니다. 정확히 보여지는 화면을 몇등분 하지 않고
// 화면에 넣은 컨텐츠를 모두 보여주려 스크롤 기능이 존재하기 때문입니다.
// 여기선 내부의 컨텐츠들 영역을 결정짓기 위해서 height 값과 margin,padding 값을 적절히 잘 이용해야 합니다.
<ScrollView style={styles.container}>
<Image style={styles.image} source={{uri:tip.image}}/>
<View style={styles.textContainer}>
<Text style={styles.title}>{tip.title}</Text>
<Text style={styles.desc}>{tip.desc}</Text>
<TouchableOpacity style={styles.button} onPress={()=>popup()}><Text style={styles.buttonText}>팁 찜하기</Text></TouchableOpacity>
</View>
</ScrollView>
)
}
const styles = StyleSheet.create({
container:{
backgroundColor:"#000"
},
image:{
height:400,
margin:10,
marginTop:40,
borderRadius:20
},
textContainer:{
padding:20,
justifyContent:'center',
alignItems:'center'
},
title: {
fontSize:20,
fontWeight:'700',
color:"#eee"
},
desc:{
marginTop:10,
color:"#eee"
},
button:{
width:100,
marginTop:20,
padding:10,
borderWidth:1,
borderColor:'deeppink',
borderRadius:7
},
buttonText:{
color:'#fff',
textAlign:'center'
}
})
>> 페이지 이동 <<
1.데이터 가지고 페이지 이동하기
버튼 카드에서 사용한 함수에 두 번째 인자로 딕셔너리를 넘겨주면, 이동한 페이지에서 넘겨준 데이터를 받을 수 있다.
// 딕셔너리로 정의되어 여러 페이지를 정의한다.
navigation.navigate(“Detail”, {
title:title
})
2.card.js : Card에서 DetailPage로 이동할 때, MainPage로부터 넘겨받은 content도 넘길 수 있다.
: 함수 및 데이터 할당
import React from 'react';
import {View, Image, Text, StyleSheet,TouchableOpacity} from 'react-native'
//MainPage로 부터 navigation 속성을 전달받아 Card 컴포넌트 안에서 사용
export default function Card({content,navigation}){
return(
//카드 자체가 버튼역할로써 누르게되면 상세페이지로 넘어가게끔 TouchableOpacity를 사용
<TouchableOpacity style={styles.card} onPress={()=>{navigation.navigate('DetailPage',content)}}>
<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>
</TouchableOpacity>
)
}
const styles = StyleSheet.create({
card:{
flex:1,
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",
}
});
3.DetailPage.js
import React,{useState,useEffect} from 'react';
import { StyleSheet, Text, View, Image, ScrollView,TouchableOpacity,Alert } from 'react-native';
export default function DetailPage({navigation,route}) {
//초기 컴포넌트의 상태값을 설정
//state, setState 뿐 아니라 이름을 마음대로 지정할 수 있음!
const [tip, setTip] = useState({
"idx":9,
"category":"재테크",
"title":"렌탈 서비스 금액 비교해보기",
"image": "https://storage.googleapis.com/sparta-image.appspot.com/lecture/money1.png",
"desc":"요즘은 정수기, 공기 청정기, 자동차나 장난감 등 다양한 대여서비스가 활발합니다. 사는 것보다 경제적이라고 생각해 렌탈 서비스를 이용하는
"date":"2020.09.09.“
})
useEffect(()=>{
console.log(route)
//Card.js에서 navigation.navigate 함수를 쓸때 두번째 인자로 content를 넘겨줬죠?
//content는 딕셔너리 그 자체였으므로 route.params에 고대~로 남겨옵니다.
//즉, route.params 는 content죠!
navigation.setOptions({
//setOptions로 페이지 타이틀도 지정 가능하고
title:route.params.title,
//StackNavigator에서 작성했던 옵션을 다시 수정할 수도 있습니다.
headerStyle: {
backgroundColor: '#000',
shadowColor: "#000",
},
headerTintColor: "#fff",
})
setTip(route.params)
},[])
const popup = () => {
Alert.alert("팝업!!")
}
const share = () => {
Share.share({
message:`${tip.title} \n\n ${tip.desc} \n\n ${tip.image}`,
});
}
return (
// ScrollView에서의 flex 숫자는 의미가 없습니다. 정확히 보여지는 화면을 몇등분 하지 않고
// 화면에 넣은 컨텐츠를 모두 보여주려 스크롤 기능이 존재하기 때문입니다.
// 여기선 내부의 컨텐츠들 영역을 결정짓기 위해서 height 값과 margin,padding 값을 적절히 잘 이용해야 합니다.
<ScrollView style={styles.container}>
<Image style={styles.image} source={{uri:tip.image}}/>
<View style={styles.textContainer}>
<Text style={styles.title}>{tip.title}</Text>
<Text style={styles.desc}>{tip.desc}</Text>
<View style={styles.buttonGroup}>
<TouchableOpacity style={styles.button} onPress={()=>popup()}><Text style={styles.buttonText}>팁 찜하기</Text></TouchableOpacity>
<TouchableOpacity style={styles.button} onPress={()=>share()}><Text style={styles.buttonText}>팁 공유하기</Text></TouchableOpacity>
<TouchableOpacity style={styles.button} onPress={()=>link()}><Text style={styles.buttonText}>외부 링크</Text></TouchableOpacity>
</View>
</View>
</ScrollView>
)
}
const styles = StyleSheet.create({
container:{
backgroundColor:"#000"
},
image:{
height:400,
margin:10,
marginTop:40,
borderRadius:20
},
textContainer:{
padding:20,
justifyContent:'center',
alignItems:'center'
},
title: {
fontSize:20,
fontWeight:'700',
color:"#eee“
},
desc:{
marginTop:10,
color:"#eee"
},
button:{
width:100,
marginTop:20,
padding:10,
borderWidth:1,
borderColor:'deeppink',
borderRadius:7
},
buttonText:{
color:'#fff',
textAlign:'center'
}
})
1. DetailPage 컴포넌트가 useState에 들어 있는 데이터 가지고 화면에 그려짐(return 함수실행)
2. 화면에 다 그려진후, useEffect 함수 실행
3. useEffect에서 상태값 변경 이벤트가 실행되면 변경된 데이터 가지고 다시 return 실행
4. 변경된 데이터를 가지고 화면에 DetailPage가 다시 그려짐.
리액트 네이티브에서 화면이 변경되는 시점은 컴포넌트의 상태값이 변경될 때이다.
처음에는, 어떠한 데이터를 보여주는 컴포넌트라면, 무조건 초기값을 의미없는 값이더라도 넣고 시작한다!
또는! 우리가 한번 배웠떤 Loading.js를 이용하여 데이터가 준비가 되면 로딩 화면을 치우고, 본 화면을 보여준다
앱에서 외부 링크를 여는 방법 : 사이트 연결이외에도 전화걸기 등의 기능이 있다.
>>Linking<<
설치 : expo install expo-linking
버튼에 연결 시킨 기능을 통해 외부 링크를 핸드폰에 있는 기본 브라우저로 열어봅니다.
expo 에서 제공해주는 도구를 설치 한다음, 해당 도구를 상단에 가져와 준비해야 합니다
import * as Linking from 'expo-linking';
DetailPage.js
import React,{useState,useEffect} from 'react';
import { StyleSheet, Text, View, Image, ScrollView,TouchableOpacity,Alert,Share } from 'react-native';
import * as Linking from 'expo-linking';
export default function DetailPage({navigation,route}) {
const [tip, setTip] = useState({
"idx":9,
"category":"재테크",
"title":"렌탈 서비스 금액 비교해보기",
"image": "https://storage.googleapis.com/sparta-image.appspot.com/lecture/money1.png",
"desc":"요즘은 정수기, 공기 청정기, 자동차나 장난감 등 다양한 대여서비스가 활발합니다. 사는 것보다 경제적이라고 생각해 렌탈 서비스를 이용하는
"date":"2020.09.09.“
})
useEffect(()=>{
console.log(route)
navigation.setOptions({
title:route.params.title,
headerStyle: {
backgroundColor: '#000',
shadowColor: "#000",
},
headerTintColor: "#fff",
})
setTip(route.params)
},[])
const popup = () => {
Alert.alert("팝업!!")
}
const share = () => {
Share.share({
message:`${tip.title} \n\n ${tip.desc} \n\n ${tip.image}`,
});
}
const link = () => {
Linking.openURL("https://spartacodingclub.kr")
}
return (
// ScrollView에서의 flex 숫자는 의미가 없습니다. 정확히 보여지는 화면을 몇등분 하지 않고
// 화면에 넣은 컨텐츠를 모두 보여주려 스크롤 기능이 존재하기 때문입니다.
// 여기선 내부의 컨텐츠들 영역을 결정짓기 위해서 height 값과 margin,padding 값을 적절히 잘 이용해야 합니다.
<ScrollView style={styles.container}>
<Image style={styles.image} source={{uri:tip.image}}/>
<View style={styles.textContainer}>
<Text style={styles.title}>{tip.title}</Text>
<Text style={styles.desc}>{tip.desc}</Text>
<View style={styles.buttonGroup}>
<TouchableOpacity style={styles.button} onPress={()=>popup()}><Text style={styles.buttonText}>팁 찜하기</Text></TouchableOpacity>
<TouchableOpacity style={styles.button} onPress={()=>share()}><Text style={styles.buttonText}>팁 공유하기</Text></TouchableOpacity>
<TouchableOpacity style={styles.button} onPress={()=>link()}><Text style={styles.buttonText}>외부 링크</Text></TouchableOpacity>
</View>
</View>
</ScrollView>
)
}
const styles = StyleSheet.create({
container:{
backgroundColor:"#000"
},
image:{
height:400,
margin:10,
marginTop:40,
borderRadius:20
},
textContainer:{
padding:20,
justifyContent:'center',
alignItems:'center'
},
title: {
fontSize:20,
fontWeight:'700',
color:"#eee"
},
desc:{
marginTop:10,
color:"#eee"
},
buttonGroup: {
flexDirection:"row",
},
button:{
width:90,
marginTop:20,
marginRight:10,
marginLeft:10,
padding:10,
borderWidth:1,
borderColor:'deeppink',
borderRadius:7
},
buttonText:{
color:'#fff',
textAlign:'center'
}
})
>>과제1<<
1.StackNavigator.js 에
import AboutPage from '../pages/AboutPage';
<Stack.Screen name="AboutPage" component={AboutPage}/> 추가
2.MainPage 에 버튼 추가
<TouchableOpacity style={styles.middleButton05} onPress={()=>{navigation.navigate('AboutPage')}}>
<Text style={styles.middleButtonText}>소개페이지</Text>
</TouchableOpacity>
3.링크연결 : AboutPage
const link = () => {
Linking.openURL("https://sensewake.tistory.com/285")
}
<TouchableOpacity style={styles.button} onPress={()=>link()}>
>>찜상태<<
Componet 폴더에 LikeCard.js : 데이터베이스 연결전까지
Pages 폴더에 LikePage.js
1.StackNavigator.js import, Stack.Screen
import LikePage from '../pages/LikePage';
2.LinckedCard.js
/MainPage로 부터 navigation 속성을 전달받아 Card 컴포넌트 안에서 사용
3.MainPage 에 버튼 추가
<ScrollView style={styles.middleContainer} horizontal indicatorStyle={"white"}>
<TouchableOpacity style={styles.middleButtonAll} onPress={()=>{category('전체보기')}}><Text style={styles.middleButtonTextAll}>전체보기</Text></TouchableOpacity>
<TouchableOpacity style={styles.middleButton01} onPress={()=>{category('생활')}}><Text style={styles.middleButtonText}>생활</Text></TouchableOpacity>
<TouchableOpacity style={styles.middleButton02} onPress={()=>{category('재테크')}}><Text style={styles.middleButtonText}>재테크</Text></TouchableOpacity>
<TouchableOpacity style={styles.middleButton03} onPress={()=>{category('반려견')}}><Text style={styles.middleButtonText}>반려견</Text></TouchableOpacity>
<TouchableOpacity style={styles.middleButton04} onPress={()=>{navigation.navigate('LikePage')}}><Text style={styles.middleButtonText}>꿀팁 찜</Text></TouchableOpacity>
</ScrollView>