💡 상세화면
1) 컴포넌트(Component) : 정해진 엘리먼트들(요소)을 사용하여 만든 화면의 일부분
2) 상태(State) : 컴포넌트에서 데이터를 유지하고 관리하기 위한 유일한 방법 == 그냥 사용할 데이터!
3) 속성(Props) : 상위 컴포넌트에서 하위 컴포넌트로 데이터를 전달하는 방식 == 그냥 데이터 전달!
4) useEffect: 화면에 컴포넌트가 그려지면 처음 실행해야 하는 함수들을 모아두는 곳
컴포넌트는 UI의 요소, 요소를 재사용 가능한 부분으로 조각내서 운영하는 기법
👉 리액트 기반으로 만들어진 페이스북 웹사이트는 운영되는 컴포넌트가 수 만가지..
App.js
의 큰 App
함수처럼, 코드 전체를 감싸고 있는 함수를 뜻하기도 함Card.js
import React from "react"
import {View,Text,Image,StyleSheet} from "react-native";
//비구조 할당 방식으로 넘긴 속성 데이터를 꺼내 사용함
export default function Card({content}) {
return (<View style={styles.card}>
<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>)
}
const styles = StyleSheet.create({
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",
}
})
MainPage.js
import React from 'react';
import main from '../assets/main.png';
import { StyleSheet, Text, View, Image, TouchableOpacity, ScrollView} from 'react-native';
import data from '../data.json';
import Card from '../components/Card';
export default function MainPage() {
console.disableYellowBox = true;
//return 구문 밖에서는 슬래시 두개 방식으로 주석
let tip = data.tip;
let todayWeather = 10 + 17;
let todayCondition = "흐림"
return (
/*
return 구문 안에서는 {슬래시 + * 방식으로 주석
*/
<ScrollView style={styles.container}>
<Text style={styles.title}>나만의 꿀팁</Text>
<Text style={styles.weather}>오늘의 날씨: {todayWeather + '°C ' + todayCondition} </Text>
<Image style={styles.mainImage} source={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 (**<Card content={content} key={i}/>**)
})
}
</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
},
});
컴포넌트에 데이터를 전달하는 것
👉 전달 모습은키
와밸류
의 형태
<Text>
태그 ⇒ numberOfLines
⇒ 말줄임표 효과<Image>
태그 ⇒ resizeMode
⇒ 이미지가 영역을 차지하는 방식<Card image={'이미지 주소'}/>
<Card/>
는 image
라는 속성 이름에 {'이미지 주소'}
값을 갖게 됨MainPage.js
에서의 Card.js
컴포넌트
- 컴포넌트에 속성(데이터)을 부여해줘서 전달할 때는, 키와 벨류(
content={content}
) 형태로 전달해줘야 할 것- 컴포넌트를 반복문 돌릴 땐, 컴포넌트마다 고유하다는 것을 표현하기 위해,
map
에서 나오는 인덱스(i)를key = {i}
속성 전달 형태로 꼭 넣을 것
Card.js
에서의 속성 값 내려 받기비구조 할당 방식
컴포넌트마다 데이터를 보유하고 관리할 수 있음
데이터라고 불러도 되지만, 리액트에서는 컴포넌트에서 보유/관리되는 데이터를 상태라고 부름
state
)는 리액트 라이브러리에서 제공해주는 useState
로 생성하고 setState
함수로 정/변경할 수 있음UI = component(state)
👉 사용자 화면(UI
)은 컴포넌트(component
)에 어떤 데이터(state
)가 주입되고, 변경되냐에 따라 변화된다를 뜻함
state
는 컴포넌트에서 관리되는 상태~너무 간단하고 유용하게 쓰이는 리액트 기본 제공 함수로,
화면이 그려진 다음 가장 먼저 실행되는 함수
useEffect(()=>{
...화면이 그려진 다음 가장 먼저 실행되야 할 코드 작성 공간
},[])
useEffect
는 데이터를 준비할 때 사용
데이터를 준비한다는 것은, 데이터를 서버로부터 혹은 어디선가로부터 받은 후 상태(state)에 반영한다는 것을 뜻함
- 화면이 그려진다.
- useEffect가 데이터를 준비한다.
- 상태 데이터가 업데이트 되었으니 화면이 다시 그려진다.
화면이 그려진 다음, 서버에게 필요한 데이터를 요청하여 받은 후, 화면을 다시 그릴 때 주로 사용됨
data.json
을 상태(state
)에 넣어서 관리해보기
MainPage.js
import React,{useState,useEffect} from 'react';
import main from '../assets/main.png';
import { StyleSheet, Text, View, Image, TouchableOpacity, ScrollView} from 'react-native';
import data from '../data.json';
import Card from '../components/Card';
export default function MainPage() {
console.disableYellowBox = true;
//return 구문 밖에서는 슬래시 두개 방식으로 주석
//useState 사용법
//[state,setState] 에서 state는 이 컴포넌트에서 관리될 상태 데이터를 담고 있는 변수
//setState는 state를 변경시킬때 사용해야하는 함수
//모두 다 useState가 선물해줌
//useState()안에 전달되는 값은 state 초기값
const [state,setState] = useState([])
//하단의 return 문이 실행되어 화면이 그려진다음 실행되는 useEffect 함수
//내부에서 data.json으로 부터 가져온 데이터를 state 상태에 담고 있음
useEffect(()=>{
setState(data)
},[])
// let tip = data.tip;
//data.json 데이터는 state에 담기므로 상태에서 꺼내옴
let tip = state.tip;
let todayWeather = 10 + 17;
let todayCondition = "흐림"
return (
/*
return 구문 안에서는 {슬래시 + * 방식으로 주석
*/
<ScrollView style={styles.container}>
<Text style={styles.title}>나만의 꿀팁</Text>
<Text style={styles.weather}>오늘의 날씨: {todayWeather + '°C ' + todayCondition} </Text>
<Image style={styles.mainImage} source={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 (<Card content={content} key={i}/>)
})
}
</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에 데이터를 넘기기 위해
상태(state)에서 tip 키 값에 접근하여 데이터를 꺼내 map 즉, 반복문을 돌리려했음
⇒ but, state에 데이터가 처음부터 있었나?
⇒ useEffect를 거쳐야 state에 데이터가 담기는데 아직 없는 상태라 오류 발생!!
Loading.js
import React from 'react';
import {View,Text,StyleSheet} from 'react-native';
export default function Loading(){
return(<View style={styles.container}><Text style={styles.title}>준비중입니다...</Text></View>)
}
const styles = StyleSheet.create({
container: {
//앱의 배경 색
flex:1,
justifyContent:'center',
alignItems:'center',
backgroundColor: '#fdc453',
},
title: {
fontSize:20,
fontWeight:'700'
}
})
MainPage.js
import React,{useState,useEffect} from 'react';
import main from '../assets/main.png';
import { StyleSheet, Text, View, Image, TouchableOpacity, ScrollView} from 'react-native';
import data from '../data.json';
import Card from '../components/Card';
import Loading from '../components/Loading';
export default function MainPage() {
console.disableYellowBox = true;
//return 구문 밖에서는 슬래시 두개 방식으로 주석
const [state,setState] = useState([])
//컴포넌트에 상태를 여러개 만들어도 됨
//관리할 상태이름과 함수는 자유자재로 정의할 수 있음
//초기 상태값으로 리스트, 참거짓형, 딕셔너리, 숫자, 문자 등등 다양하게 들어갈 수 있음.
const [ready,setReady] = useState(true)
useEffect(()=>{
//뒤의 1000 숫자는 1초를 뜻함
//1초 뒤에 실행되는 코드들이 담겨 있는 함수
setTimeout(()=>{
setState(data)
setReady(false)
},1000)
},[])
// let tip = data.tip;
let tip = state.tip;
let todayWeather = 10 + 17;
let todayCondition = "흐림"
**//처음 ready 상태값은 true 이므로 ? 물음표 바로 뒤에 값이 반환(그려짐)됨
//useEffect로 인해 데이터가 준비되고, ready 값이 변경되면 : 콜론 뒤의 값이 반환(그려짐)**
return **ready ? <Loading/>** : (
/*
return 구문 안에서는 {슬래시 + * 방식으로 주석
*/
<ScrollView style={styles.container}>
<Text style={styles.title}>나만의 꿀팁</Text>
<Text style={styles.weather}>오늘의 날씨: {todayWeather + '°C ' + todayCondition} </Text>
<Image style={styles.mainImage} source={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 (<Card content={content} key={i}/>)
})
}
</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
},
});
👉
ready
라는 새로운 상태값 추가
useEffect
안에 있는setTimeout
함수
⇒ 뒤에 있는 숫자(1000 === 1초) 만큼, 지연됐다가 안에 있는 코드가 실행되는 지연 함수
- 진행되는 순서
1)ready
값이true
이므로return
구문에서?
물음표 바로 뒤의Loading
컴포넌트가 화면에 그려짐
2) 화면이 그려지고 난다음, 1초 이따가 상태값들이 채워지고 변경됨
3)ready
상태 값이false
가 됨
4) 상태값이 변경되었으므로 화면이 다시 그려짐
5)ready
값이false
이므로return
구문에서:
콜론 뒤의MainPage
컴포넌트가 화면에 그려짐
하단의 데이터가 카테고리에 맞게 다시 정렬되는 기능
⇒ 상태값이 바뀌면 화면이 다시 그려져야 함
카테고리의 기능을 위해서는 먼저 카테고리 상태
가 필요
👉 카테고리에 맞는 꿀팁들을 지속적으로 저장하고 관리할 상태 그릇!
함수
필요
👉 카테고리에 따라 카테고리 상태 데이터를 새롭게 구성해주는 기능을 하는 함수!
MainPage.js
import React,{useState,useEffect} from 'react';
import main from '../assets/main.png';
import { StyleSheet, Text, View, Image, TouchableOpacity, ScrollView} from 'react-native';
import data from '../data.json';
import Card from '../components/Card';
import Loading from '../components/Loading';
export default function MainPage() {
console.disableYellowBox = true;
//return 구문 밖에서는 슬래시 두개 방식으로 주석
//기존 꿀팁을 저장하고 있을 상태
**const [state,setState] = useState([])**
//카테고리에 따라 다른 꿀팁을 그때그때 저장관리할 상태
**const [cateState,setCateState] = useState([])**
//컴포넌트에 상태를 여러개 만들어도 됨
//관리할 상태이름과 함수는 자유자재로 정의할 수 있음
//초기 상태값으로 리스트, 참거짓형, 딕셔너리, 숫자, 문자 등등 다양하게 들어갈 수 있음.
const [ready,setReady] = useState(true)
useEffect(()=>{
//뒤의 1000 숫자는 1초를 뜻함
//1초 뒤에 실행되는 코드들이 담겨 있는 함수
setTimeout(()=>{
//꿀팁 데이터로 모두 초기화 준비
let tip = data.tip;
setState(tip)
setCateState(tip)
setReady(false)
},1000)
},[])
const category = (cate) => {
if(cate == "전체보기"){
//전체보기면 원래 꿀팁 데이터를 담고 있는 상태값으로 다시 초기화
setCateState(state)
}else{
setCateState(state.filter((d)=>{
return d.category == cate
}))
}
}
let todayWeather = 10 + 17;
let todayCondition = "흐림"
//처음 ready 상태값은 true 이므로 ? 물음표 바로 뒤에 값이 반환(그려짐)됨
//useEffect로 인해 데이터가 준비되고, ready 값이 변경되면 : 콜론 뒤의 값이 반환(그려짐)
return ready ? <Loading/> : (
/*
return 구문 안에서는 {슬래시 + * 방식으로 주석
*/
<ScrollView style={styles.container}>
<Text style={styles.title}>나만의 꿀팁</Text>
<Text style={styles.weather}>오늘의 날씨: {todayWeather + '°C ' + todayCondition} </Text>
<Image style={styles.mainImage} source={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}/>)
})
}
</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
},
});
📌이 포스팅의 모든 자료의 출처와 저작권은 SpartaCodingClub 강의에 있습니다.📌