일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 |
- 딥러닝
- HTTP
- 리액트 네이티브 프로젝트 생성
- 깃허브 토큰 인증
- 깃 터미널 연동
- 데베
- 백준 4358 자바
- 팀플회고
- 백준
- 백준 5525번
- 모두의네트워크
- 머신러닝
- 모두를위한딥러닝
- 모두를 위한 딥러닝
- 백준 4358번
- 깃허브 로그인
- 데이터베이스
- 자바
- SQL
- 깃 연동
- 모두의 네트워크
- 스터디
- 정리
- 리액트 네이티브 시작하기
- 리액트 네이티브
- 문자열
- 백준 4949번
- 네트워크
- React Native
- 지네릭스
- Today
- Total
솜이의 데브로그
[React Native] 컴포넌트 본문
Reference : 처음 배우는 리액트 네이티브 (김범준)
컴포넌트
- 재사용이 가능한 조립 블록으로 화면에 나타나는 UI 요소이다.
- 부모로부터 받은 속성이나 자신의 상태에 따라 표현이 달라지고 다양한 기능을 수행한다.
내장 컴포넌트
https://reactnative.dev/docs/button
리액트 네이티브에는 위와 같은 다양한 내장 컴포넌트들이 제공된다.
src/App.js
import React from 'react';
import {Text, View, Button} from 'react-native';
const App = () => {
return (
<View
style={{
flex : 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
}}
>
<Text style={{ fontSize: 30, marginBottom: 10}}>Button Component</Text>
<Button title="Button" onPress={() => alert('Click!!!')} />
</View>
);
};
export default App;
title 속성 : 버튼 내부에 출력되는 텍스트
onPress 속성 : 버튼이 눌렸을 때 호출되는 함수를 지정
즉, title 속성을 이용해 Button 이라고 지정하고, 버튼을 클릭했을 때 Click !!! 이라는 창이 나타나도록 지정.
import App from './src/App';
export default App;
루트의 App.js 파일은 수정해서 위의 컴포넌트를 사용하도록 수정한다.
결과
아이폰에서의 화면은 버튼이 다르게 표시된다. 이는 Button 컴포넌트 문서의 color 속성하면된다.
iOS에서는 텍스트 색을 나타내는 값이지만 안드로이드에는 버튼의 바탕색을 나타내기 때문.
따라서 한 플랫폼만 테스트하는 것이 아니라 iOS와 안드로이드 모두 확인하면서 개발하는 것이 좋다.
커스텀 컴포넌트 만들기
src 폴더 밑에 components 폴더 생성 후, 커스톰 컴포넌트인 myButton 파일을 생성한다.
import React from 'react';
import {TouchableOpacity, Text} from 'react-native';
const MyButton = () => {
return(
<TouchableOpacity>
<Text Style={{FontSize: 24}}>My Button</Text>
</TouchableOpacity>
);
};
export default MyButton;
Pressable 컴포넌트를 사용해 클릭에 대해 상호작용 할 수 있도록 하고, 버튼에 내용을 표시하기 위해 Text 컴포넌트를 이용했다.
이후 App 컴포넌트에서 위의 컴포넌트를 이용하도록 한다.
import React from 'react';
import {TouchableOpacity, Text} from 'react-native';
const MyButton = () => {
return(
<TouchableOpacity
style={{
backgroundColor: '#3498db',
padding: 16,
margin: 10,
borderRadius: 8,
}}
onPress={()=> alert('Click!!!')}
>
<Text Style={{FontSize: 24}}>My Button</Text>
</TouchableOpacity>
);
};
export default MyButton;
이런식으로 수정해서 버튼 클릭 시 알림창 띄우도록 할 수 있다.
props와 state
props
properties를 줄인 표현으로, 부모 컴포넌트로부터 전달된 속성값 혹은 상속받은 속성값을 말한다.
부모 컴포넌트가 자식 컴포넌트의 props를 설정하면 자식 컴포넌트에서는 해당 props를 사용할 수 있지만 변경은 불가능하다.
import React from 'react';
import {TouchableOpacity, Text} from 'react-native';
const MyButton = props => {
console.log(props);
return(
<TouchableOpacity
style={{
backgroundColor: '#3498db',
padding: 16,
margin: 10,
borderRadius: 8,
}}
onPress={()=> alert('Click!!!')}
>
<Text Style={{ color: 'white', FontSize: 24}}>{props.title}</Text>
</TouchableOpacity>
);
};
export default MyButton;
다음과 같이 부모로부터 전달된 props를 함수의 파라미터로 받아서 사용 가능하다. log 찍어보면 전달된 값을 확인 가능.
부모컴포넌트에서 자식 컴포넌트를 사용하면서 속성으로 props 전달하는 방법 외에도 태그 사이에 값을 입력해서 전달도 가능하다.
src/App.js
import React from 'react';
import {Text, View, Button} from 'react-native';
import MyButton from './components/MyButton';
const App = () => {
return (
<View
style={{
flex : 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
}}
>
<Text style={{ fontSize: 30, marginBottom: 10 }}>Props</Text>
<MyButton title="Button" />
<MyButton title = "Button">Children Props</MyButton>
</View>
);
};
export default App;
위처럼 태그 사이에 전달된 값은 자식 컴포넌트의 props에 children으로 전달된다.
src/components/MyButton.js
import React from 'react';
import {TouchableOpacity, Text} from 'react-native';
const MyButton = props => {
return(
<TouchableOpacity
style={{
backgroundColor: '#3498db',
padding: 16,
margin: 10,
borderRadius: 8,
}}
onPress={()=> alert('Click!!!')}
>
<Text Style={{ color: 'white', FontSize: 24}}>
{props.children || props.title}
</Text>
</TouchableOpacity>
);
};
export default MyButton;
props에 children이 있다면 title보다 우선시되도록 작성한다.
default Props
컴포넌트를 잘못 파악해 반드시 전달되어야 하는 중요한 값이 전달되지 않았을 때 사용할 기본 값을 defaultProps로 지정한다.
prop-type 라이브러리를 추가로 설치해 컴포넌트에서 전달받아야 하는 props 타입과 필수 여부를 지정.
npm install prop-types
MyButton.js 파일을 다음과 같이 수정
import React from 'react';
import {TouchableOpacity, Text} from 'react-native';
import PropTypes from 'prop-types';
const MyButton = props => { ... };
MyButton.propTypes = {
title: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
};
export default MyButton;
다음과 같이 설정했는데 name 을 전달하지 않는 경우 다음과 같은 오류가 발생한다
title은 defaultProps에서 title의 기본 값을 설정했으므로 title이 전달되지 않아도 경고 메시지가 나타나지 않는다.
PropTypes에는 이외에도 함수, 객체, 배열 등의 다양한 타입을 지정할 수 있다.
state
- state는 컴포넌트 내부에서 생성되고 값을 변경할 수 있으며 이를 이용해 컴포넌트 상태를 관리한다.
- 상태란 컴포넌트에서 변화할 수 있는 값을 나타내며, 상태가 변하면 컴포넌트는 리렌더링된다.
- 과거에는 함수형 컴포넌트에서 상태를 관리할 수 없어 상태를 관리해야하는 컴포넌트는 반드시 클래스형 컴포넌트를 사용해야 했다.
- 하지만 리액트 16.8 버전부터는 Hooks를 사용해 함수형 컴포넌트에서도 상태를 관리할 수 있게 되었다.
useState
const [state, setState] = useState(initialState);
상태를 관리하는 변수와 그 변수를 변경할 수 있는 세터 함수를 배열로 반환한다.
useState함수를 호출할 때 파라미터에 생성되는 상태의 초깃값을 전달할 수 있고, 전달하지 않으면 undefined로 설정되어 에러가 발생할 수 있으므로 항상 초깃값을 설정하는 것이 좋다.
src/components/Counter.js
import React, {useState} from 'react';
import { View, Text } from 'react-native';
import MyButton from './MyButton';
const Counter = () => {
const[count, setCount] = useState(0);
return(
<View style={{ alignItems: 'center'}}>
<Text style={{ fontSize: 30, margin: 10 }}>{count}</Text>
<MyButton title="+1" onPress={()=> setCount(count+1)} />
<MyButton title="-1" onPress={()=> setCount(count-1)} />
</View>
);
};
export default Counter;
- setCount 세터 함수를 만들고, count의 초깃값은 0으로 설정한다.
- MyButton 컴포넌트를 이용해 현재 count 값에서 +1, -1 버튼을 생성 후
- 결과를 Text 컴포넌트를 이용해 현재 count 값을 볼 수 있도록 한다.
src/App.js
import React from 'react';
import {Text, View, Button} from 'react-native';
import MyButton from './components/MyButton';
import Counter from './components/Counter';
const App = () => {
return (
<View
style={{
flex : 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
}}
>
<Counter />
</View>
);
};
여러개의 useState
컴포넌트에서 관리해야 하는 상태가 여러개인 경우, 관리해야하는 상태의 수만큼 useState를 사용.
import React, {useState} from 'react';
import { View, Text } from 'react-native';
import MyButton from './MyButton';
const Counter = () => {
const[count, setCount] = useState(0);
const[double, setDouble] = useState(0);
return(
<View style={{ alignItems: 'center'}}>
<Text style={{ fontSize: 30, margin: 10 }}>count: {count}</Text>
<Text style={{ fontSize: 30, margin: 10 }}>double: {double}</Text>
<MyButton
title="+"
onPress={()=> {
setCount(count+1);
setDouble(double+2);
}}
/>
<MyButton
title="-"
onPress={()=> {
setCount(count-1);
setDouble(double-2);
}}
/>
</View>
);
};
export default Counter;
이벤트
- 리액트 네이티브는 사용자의 행동에 따라 상호 작용하는 이벤트를 다양하게 제공한다.
press 이벤트
웹 프로그래밍에서 가장 많이 사용하는 이벤트 중 하나는 사용자가 특정 DOM을 클릭했을 때 호출되는 onClick 이벤트일 것이다.
리액트 네이티브에서 onClick 기능과 가장 비슷한 이벤트는 press 이벤트이다.
TouchableOpacity 컴포넌트에서 설정할 수 있는 Press 이벤트의 종류는 총 네가지 이다.
- onPressIn : 터치가 시작될때 항상 호출
- onPressOut : 터치가 해체될 때 항상 호출
- onPress : 터치가 해제될 때 onPressOut 이후 호출
- onLongPress : 터치가 일정 시간 이상 지속되면 호출
src/components/EventButton.js
import React from 'react';
import { TouchableOpacity, Text } from 'react-native';
const EventButton = () => {
const _onPressIn = () => console.log('Press In !!!\n');
const _onPressOut = () => console.log('Press Out !!!\n');
const _onPress = () => console.log('Press !!!\n');
const _onLongPress = () => console.log('Long Press !!!\n');
return(
<TouchableOpacity
style={{
backgroundColor: '#f1c40f',
padding: 16,
margin: 10,
borderRadius: 8,
}}
onPressIn={_onPressIn}
onLongPress={_onLongPress}
onPressOut={_onPressOut}
onPress={_onPress}
>
<Text style={{color: 'white', fontSize: 24 }}>Press</Text>
</TouchableOpacity>
);
};
export default EventButton;
src/App.js 수정
import EventButton from './components/EventButton';
const App = () => {
return (
<View
style={{
flex : 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
}}
>
<EventButton />
</View>
);
};
결과
다음과 같이 버튼을 클릭하면
- onPressIn > onPressOut > onPress
- onPressIn > onLongPress > onPressOut
순으로 호출 된다. onPressIn과 onPressOut은 항상 호출되지만, onPress와 onLongPress 는 사용자가 클릭하는 시간에 따라 둘 중 하나만 호출된다.
호출되는 시간을 조절하고 싶다면 delayLongPress값을 조절해서 원하는 시간으로 설정할 수 있다.
ex)
return(
<TouchableOpacity
style={{
backgroundColor: '#f1c40f',
padding: 16,
margin: 10,
borderRadius: 8,
}}
onPressIn={_onPressIn}
onLongPress={_onLongPress}
onPressOut={_onPressOut}
onPress={_onPress}
delayLongPress={3000}
>
<Text style={{color: 'white', fontSize: 24 }}>Press</Text>
</TouchableOpacity>
);
change 이벤트
변화를 감지하는 change 이벤트는 값을 입력하는 TextInput 컴포넌트에서 많이 사용된다.
src/components/EventInput.js
import React, { useState } from 'react';
import { View, Text, TextInput } from 'react-native';
const EventInput = () => {
const[text, setText] = useState('');
const _onChange = event => setText(event.nativeEvent.text);
return(
<View>
<Text style={{margin: 10, fontSize= 30}}>text: {text}</Text>
<TextInput
style={{ borderWidth: 1, padding: 10, fontSize: 20}}
placeholder="Enter a text..."
onChange={_onChange}
/>
</View>
);
};
export default EventInput;
TextInput 컴포넌트의 onChange 속성은 컴포넌트에 입력된 텍스트가 변경될 때 호출된다.
또한 호출되는 함수에는 다음과 같은 형태로 인자를 전달한다.
{
...,
"nativeEvent": {
"eventCount": ...,
"target": ...,
"text": ...,
},
...
}
여기서 우리는 변화된 텍스트만 출력하므로, event.nativeEvent.text를 setText에 전달하여 출력하도록 한다.
우리는 여기서 변화된 텍스트만 필요하므로 onChangeText 를 이용하여 변경된 텍스트의 문자열만 인수로 전달할 수 있다.
Pressable 컴포넌트
리액트 네이티브 0.63버전부터 TouchableOpacity 컴포넌트를 대체하는 Pressable 컴포넌트가 추가되었다.
기존 컴포넌트들과 다른 특징은 HitRect와 PressRect이다.
HitRect를 사용해 버튼모양보다 약간 떨어진 부분까지 이베트가 발생할 수 있도록 한다.
PressRect 기능을 이용해 버튼을 누른 상태에서 벗어날 수 있는 범위를 지정한다.
import React from 'react';
import {Text, View, Pressable} from 'react-native';
import MyButton from './components/MyButton';
import Counter from './components/Counter';
import EventButton from './components/EventButton';
import EventInput from './components/EventInput';
const Button = (props) => {
return(
<Pressable
style={{padding: 10, backgroundColor: '#1abc9c'}}
onPressIn={() => console.log('Press In')}
onPressOut={() => console.log('Press Out')}
onPress={() => console.log('Press')}
onLongPress={() => console.log('Long Press')}
delayLongPress={3000}
pressRetentionOffset={{bottom: 50, left: 50, right: 50, top: 50}}
hitSlop={50}>
<Text style={{padding: 10, fontSize: 30}}>{props.title}</Text>
</Pressable>
);
};
const App = () => {
return (
<View
style={{
flex : 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
}}
>
<Button title="Pressable" />
</View>
);
};
PressRect의 범위는 HitRect의 범위 끝에서부터 시작되므로 hitSlop의 값에 따라 PressRect의 범위가 달라진다.
타입을 지정해서 문제를 찾아내느 방법으로 PropTypes 외에 타입 스크립트나 플로우를 사용하는 방법이 있다.
느낀점
프론트 공부는 처음인데 안드로이드스튜디오 공부하면서 비슷한게 많이 나와서 생각했던것보다 낯설지는 않았다.
그리고 프론트가 왜 재밌는지도 알겠다. 수정하면 바로바로 확인이 가능하니까 성취감이(?) 백보다 좀 더 많이 오는듯하다ㅋㅋ
대신 낯선 언어들도 열심히 공부해야하고 타자 오타.. 안내고 괄호같은거 확인 꼼꼼하게 잘 해야 할 것 같다.
시간이 되면 JS 공부도.. 좀 더 탄탄히 해보고싶다.
'dev > React native' 카테고리의 다른 글
[React Native] 할 일 관리 애플리케이션(1) (0) | 2021.11.05 |
---|---|
[React Native] 스타일링 (0) | 2021.10.16 |
[React Native] JSX (0) | 2021.10.10 |
[React Native] 리액트 네이티브 프로젝트 만들기 (윈도우) (0) | 2021.10.08 |
리액트 네이티브란? (0) | 2021.10.07 |