Button 표현 방법
리액트 네이티브에서는 다양한 내장 컴포넌트(core components)를 제공한다.
ex. View, Text, Button..
같은 컴포넌트일지라도 iOS, 안드로이드에서 다르게 표현될 수 있기 때문에 두 플랫폼으로 다 테스트해 보는 것이 중요하다. 즉 컴포넌트 속성이 다르게 표현될 수 있기 때문에 커스텀 컴포넌트를 만들어 문제를 해결해 볼 수 있다.
아래는 그 예시이다.
<Button>의 color 속성은 iOS에서 text color를 나타내지만, 안드로이드에서는 버튼의 배경색을 나타낸다. 따라서 의도한 결과와 다르게 나오기 때문에 Button 컴포넌트를 대체할 TouchableOpacity + Text 조합을 만들 수 있다.
Button → TouchableOpacity + Text → Pressable
import React from 'react'; // JSX는 React.createElement를 호출하는 코드로 컴파일되므로 컴포넌트 작성 시 반드시 작성해야 하는 코드
import { Text, TouchableOpacity } from 'react-native';
import PropTypes from 'prop-types';
const MyButton = props => {
console.log(props);
return (
<TouchableOpacity
style={{
backgroundColor: '#3498db',
padding: 16,
margin: 10,
borderRadius: 8,
}}
onPress={() => props.onPress()}>
<Text style={{ color: 'white', fontSize: 24 }}>{props.children || props.title}</Text>
{/*true이면 평가를 멈추고 해당 피연산자 변환 전의 값 반환*/}
</TouchableOpacity>
);
};
MyButton.defaultProps = { // default 값 전달
title: 'Button',
};
MyButton.propTypes = { // 잘못된 타입이나 미입력 방지 위해 propTypes 사용
title: PropTypes.string.isRequired,
onPress: PropTypes.func.isRequired
};
export default MyButton;
/* App.js */
import React from 'react';
import { Text, View } 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" onPress={() => alert('props')}/>
<MyButton title="Button" onPress={() => alert('children')}>Children Props</MyButton>
<MyButton onPress={() => alert('default')} />
</View>
);
};
export default App;
- TouchableOpacity 컴포넌트에는 사실 onPress 속성이 없지만, TouchableWithoutFeedBack 컴포넌트를 상속받으며 그의 속성인 onPress 속성을 사용할 수 있다.
- props(properties): 부모 컴포넌트로부터 전달된 속성값 혹은 상속받은 속성값, 부모 컴포넌트가 자식 컴포넌트의 props를 설정하여 자식 컴포넌트에서 해당 props를 사용할 수 있지만 변경은 불가능하다. 변경이 필요한 경우 부모 컴포넌트에서 이루어진다.
props를 터미널에 찍어보면 이렇게 객체 형태로 들어온다.
- onPress: 이벤트 핸들러 함수로 버튼이 클릭되었을 때 실행되는 함수
- children: 컴포넌트 내부에 포함될 자식 요소, 즉 태그 사이에 있는 텍스트
- title: 버튼에 표시될 텍스트
객체 타입으로 전달되니 props.title, props.children.. 이런 식으로 사용된다.
state
이전 포스팅에서도 적어두었지만 어느새 머릿 속에서 증발해버려 여기서도 짤막하게 기록해 두기... 흑
props는 부모 컴포넌트에서 받은 값으로, 변경할 수 없는 반면에 state는 컴포넌트 내부에서 생성되고 값을 변경할 수 있다. 다시 말하면, state는 컴포넌트에서 변화할 수 있는 값을 나타낸다.
컴포넌트는 크게 함수형 컴포넌트, 클래스형 컴포넌트가 있는데 전자는 상태를 관리할 수 없었고 후자는 가능했다. 하지만 후자는 class, render() 함수를 반드시 선언해야 했고, Component 상속 등을 해야 했어서 함수형 컴포넌트보다 더 복잡하다는 단점이 있었다. 그때 리액트 16.8버전 이후 Hooks 훅이 등장하며 상태를 관리할 수 있게 되면서 '함수형 컴포넌트 + Hooks' 조합을 일반적으로 사용하게 되었다.
https://velog.io/@shinyejin0212/React-클래스형-컴포넌트에서-함수형-컴포넌트로-바뀐-이유
const [state, setState] = useState(initialState); // 배열 형태로 반환
- state: 상태를 관리하는 변수
- setState: 그 변수를 변경할 수 있는 세터(setter) 함수
event
1. press 이벤트
- onPressIn: 터치가 시작될 때 항상 호출
- onPressOut: 터치가 해제될 때 항상 호출
- onPress: 터치가 해제될 때 onPressOut 이후 호출
- onLongPress: 터치가 일정 시간 이상 지속되면 호출 -- delayLongPress 값을 조절 가능
2. change 이벤트
변화를 감지하는 change 이벤트는 TextInput 컴포넌트에서 많이 사용된다.
- onChange(): 컴포넌트의 텍스트가 변경되었을 때 아래 박스와 같은 형태로 인자를 전달한다.
- onChangeText(): 컴포넌트의 텍스트가 변경되었을 때 변경된 텍스트의 문자열만 인수로 전달한다.
{
...,
"nativeEvent": {
"eventCount": ...,
"target": ...,
"text": ...,
},
...
}
import { useState, React } from "react";
import { Text, TextInput, View } from "react-native";
const EventInput = () => {
const [text, setText] = useState('');
const _onChange = event => setText(event.nativeEvent.text);
const _onChangeText = text => setText(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} /* nativeEvent 객체를 전달 */
onChangeText={_onChangeText} /* 둘이 같은데 이건 컴포넌트의 텍스트가 변경되었을 때 "변경된 텍스트의 문자열만" 인수로 전달하며 호출 */
/>
</View>
);
};
export default EventInput;
onChange()는 객체 형태로 반환하기 때문에 세터 함수 안에 event.nativeEvent.text로 지정하지만, onChangeText()는 텍스트의 문자열만을 지정하여 간편하게 사용할 수 있다. 두 함수의 기능은 같다.
3. Pressable 이벤트
TouchableOpacity 컴포넌트처럼 위의 press 이벤트들을 사용할 수 있는데 기존의 컴포넌트들과 다른 점이 있다면,
- HitRect -- hitSlop
- PressRect -- pressRetentionOffset
이 있다. 버튼에서 약간 벗어난 곳을 클릭했을 때도 이벤트를 발생할 수 있게 하거나, 반대로 버튼을 실수로 눌렀을 때 버튼의 실제 위치로부터 어느 정도까지를 벗어났다고 봐줄 것인지를 정하기 위한 이벤트이다. PressRect의 범위는 HitRect의 범위 끝에서부터 시작되므로 hitSlop의 값에 따라 PressRect의 범위가 달라진다.
import React from 'react';
import {View, Text, Pressable} from 'react-native';
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,
justifyContent: 'center',
backgroundColor: '#fff',
alignItems: 'center',
}}>
<Button title="Pressable" />
</View>
);
};
export default App;
'FrontEnd > React Native' 카테고리의 다른 글
[RN] 연산자 종류 (==, !=, ===, !==) (0) | 2024.05.22 |
---|---|
[RN] Props 중괄호 사용 (feat. 구조 분해 할당) (0) | 2024.05.22 |
[RN] git, GitHub (0) | 2024.05.10 |
[RN] JSX 문법 _ 처음 배우는 리액트 네이티브 (24.05.08) (0) | 2024.05.08 |
[앱개발교육] React 개요 및 chatGPT에서 알게 된 것 (0) | 2024.03.08 |