리액트 컴포넌트, 속성, 상태
리액트 기초지식
컴포넌트(Component) : 정해진 요소를 사용하여 만든 화면의 일부분
상태(State) : 컴포넌트에서 데이터를 유지하고 관리하기 위한 방법 = 데이터
속성(Props) : 상위 컴포넌트에서 하위 컴포넌트로 데이터를 전달하는 방식 = 데이터 전달
useEffect : 화면에 컴포넌트가 그려지면 처음 실행해야 하는 함수들을 모아두는 곳
Component에 있는 Props가 데이터를 전달 → Component 안의 State가 데이터를 관리
컴포넌트(Component)
//비구조 할당 방식으로 넘긴 속성 데이터를 꺼내 사용함
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>)
}
import Card from '../components/Card';
...
<View style={styles.cardContainer}>
{/* 하나의 카드 영역을 나타내는 View */}
{
tip.map((content,i)=>{
return (<Card content={content} key={i}/>)
})
}
</View>
MainPage.js에서 Card.js로 content라는 데이터를 넘겼다.
속성(Props)
key와 value의 형태 (ex. content={content})
컴포넌트에 대해 map
으로 반복문 → 반드시 인덱스(i)를 key={i}
로 속성 전달
상태(useState)와 useEffect
컴포넌트마다 보유, 관리하는 데이터를 상태
라고 한다.
리액트에서 상태(state) → useState
로 생성, setState
로 변경 가능
useState
리액트에서 화면은 데이터에 따라 변경되고, 상태(state)로 관리되는 데이터가 변경되면 화면이 바뀐다.
useEffect
useEffect(()=>{
화면이 그려지고 나서 가장 먼저 실행돼야 할 코드
},[])
데이터를 준비(데이터를 받고 상태(state)에 반영)할 때 사용
화면이 그려진다 → useEffect가 데이터를 준비 → 상태 데이터가 업데이트 되었으니 다시 화면이 그려진다
const [state, setState] = useState([])
useEffect(()=>{
setState(data)
},[])
state : 컴포넌트에서 관리될 상태 데이터를 담고 있는 변수
setState : state를 변경시킬 때 사용해야하는 함수
useState() 안에 전달되는 것 → state 초기값
useEffect 함수로 data.json에서 가져온 데이터를 state에 담음
로딩 화면
useEffect는 화면이 그려지고 나서 실행되는데, 현재는 화면을 그릴 때 이용할 state에 값이 설정되어 있지 않은 상태임
따라서 로딩 화면 을 먼저 그린 후 → useEffect를 통해 state를 설정하고 나서 → 메인 화면을 그려야 오류가 나지 않음
Loading.js 파일 생성 후 MainPage.js를 다음과 같이 수정
import Loading from '../components/Loading';
const [state,setState] = useState([])
const [ready,setReady] = useState(true) //초기 ready : True
useEffect(()=>{
setTimeout(()=>{
setState(data)
setReady(false)
},1000) //1000 = 1초
},[])
setTimeout으로 1초 뒤에 상태 관리에 들어가게 함
return ready ? <Loading/> : (
<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}>
{
tip.map((content,i)=>{
return (<Card content={content} key={i}/>)
})
}
</View>
</ScrollView>
);
삼항연산자를 이용해서 ready가 true
이면 로딩 화면을, false
이면 메인 화면을 그린다.
실행 순서
초기 ready 상태는 true
여서 로딩 화면을 먼저 그림
useEffect가 실행돼서 1초 뒤에 state 값을 설정, ready를 false
로 변경
ready 상태가 변경되었으니 자동으로 retrun ready ? ...
가 실행됨
false
이므로 메인 화면이 그려짐
카테고리 기능
MainPage.js
const [state,setState] = useState([]) //전체 리스트
const [cateState,setCateState] = useState([]) //카테고리 선택에 따른 리스트
const [ready,setReady] = useState(true)
useEffect(()=>{
setTimeout(()=>{
let tip = data.tip;
setState(tip)
setCateState(tip) //처음 로딩 시 전체 리스트로 초기화
setReady(false)
},1000)
},[])
선택한 카테고리에 따라 보여줄 리스트를 저장하는 cateState
useEffect에서 cateState를 tip (전체 데이터) 으로 초기화
<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>
카테고리 버튼마다 onPress 함수를 설정함
category 함수에 카테고리 이름을 넘겨주도록 함
const category = (cate) => {
if(cate == "전체보기"){
//전체보기면 원래 꿀팁 데이터를 담고 있는 상태값으로 다시 초기화
setCateState(state)
}else{ //전체(state)에서 선택한 카테고리 데이터만 추출
setCateState(state.filter((d)=>{
return d.category == cate //true일때 cateSate에 넣는다
}))
}
}
category 함수에는 cate(카테고리 이름) 파라미터가 있음
전체보기를 클릭했다면 cateState를 전체 데이터(state)로 변경
그 외 카테고리 버튼을 클릭했다면 전체 데이터(state) 중 해당 카테고리에 속하는 데이터만 cateState에 저장 (filter
함수 이용)
스택네비게이터
네비게이션
컴포넌트들을 페이지화 시켜서 해당 페이지끼리 이동을 가능하게 하는 라이브러리
도구 설치
yarn add @react-navigation/native
expo install react-native-gesture-handler react-native-reanimated react-native-screens react-native-safe-area-context @react-native-community/masked-view
스택네비게이션
컴포넌트에 페이지 기능 부여, 컴포넌트에서 컴포넌트로 이동할 수 있도록 해준다.
Stack.Navigator
: 책갈피 (모든 페이지를 등록시킬 곳)
설치
yarn add @react-navigation/stack
적용하기
import { createStackNavigator } from '@react-navigation/stack';
//페이지로 만들 컴포넌트 불러오기
import DetailPage from '../pages/DetailPage';
import MainPage from '../pages/MainPage';
const Stack = createStackNavigator();
const StackNavigator = () =>{
return (
<Stack.Navigator
screenOptions={{
headerStyle: {
backgroundColor: "black",
borderBottomColor: "black",
shadowColor: "black",
height:100
},
headerTintColor: "#FFFFFF",
headerBackTitleVisible: false
}}
>
//페이지로 만들 컴포넌트
<Stack.Screen name="MainPage" component={MainPage}/>
<Stack.Screen name="DetailPage" component={DetailPage}/>
</Stack.Navigator>
)
}
export default StackNavigator;
import React from 'react';
import { StatusBar } from 'expo-status-bar';
import {NavigationContainer} from '@react-navigation/native';
import StackNavigator from './navigation/StackNavigator'
export default function App() {
console.disableYellowBox = true;
return (
<NavigationContainer>
<StatusBar style="black" />
<StackNavigator/>
</NavigationContainer>);
}
앱의 가장 최상위 컴포넌트인 App.js에 네비게이션 기능을 달아준 것
NavigationContainer 태그로 StatusBar(상태바)과 StackNavigator(직접 만든 스택네비게이션)을 감싼다.
💡
Stack.screen에 등록된 모든 페이지 컴포넌트들은 navigation
과 route
라는 딕셔너리(객체)를 속성으로 넘겨받아 사용할 수 있다!
navigation.setOptions({
title:'나만의 꿀팁'
})
navigation.navigate("DetailPage")
navigation.navigate("DetailPage",{
title: title
})
const { title} = route.params; //비구조 할당방식
navigation
setOptions : 제목, 헤더 옵션 스타일 등 바꿀 수 있음
navigate : 해당 페이지로 이동하는 함수 (StackNavigator.js의 Stack.screen name 속성), 두번째 매개변수로 딕셔너리 데이터 전달
route
: navigate로 인해 전달받은 데이터를 받는 딕셔너리
공유하기 기능
React Native 자체에서 제공하는 기능이다.
import { Share } from "react-native";
export default function DetailPage({navigation,route}) {
...
const share = () => {
Share.share({
message:`${tip.title} \n\n ${tip.desc} \n\n ${tip.image}`,
});
}
return (
<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>
</View>
</View>
</ScrollView>
)
}
share 함수를 이용해 공유할 때 전달할 제목, 설명, 이미지 등을 설정할 수 있음
외부 링크 클릭 이벤트
도구 설치
expo install expo-linking
적용하기
import * as Linking from 'expo-linking';
const link = () => {
Linking.openURL("https://spartacodingclub.kr")
}
<TouchableOpacity style={styles.button} onPress={()=>link()}><Text style={styles.buttonText}>외부 링크</Text></TouchableOpacity>
Uploaded by Notion2Tistory v1.1.0