[React-Native]Touch event, Button
개발환경 시작하기
이제 개발환경 시작하기는 생략하도록 하겠습니다
react_native_01이라는 새로운 프로젝트를 생성하여 진행하였습니다.
react-native init react_native_02
에뮬레이터까지 틀어주도록 합시다
Setup : Component 분리
외부파일에 작성한 것을 import하여 사용하는 방법(현업에서 많이 사용)
별도의 외부파일을 작성하여, App.js에 불러와 하나의 컴포넌트처럼 사용해보자. (코드가 간결해지고 유지보수가 쉬워짐!)
header.js라는 파일을 작성하여, App.js에 불러오는 방식을 사용할 것
src폴더를 만들어서 거기에 header.js라는 파일을 하나 만들어 줍니다.
header.js
/**
* Sample React Native App
* https://github.com/facebook/react-native
*
* @format
* @flow strict-local
*/
import React from 'react';
import {View, Text, StyleSheet} from 'react-native';
//참고 : jsx component를 return하므로 () => (이부분이 소괄호)
const Header = () => (
<View style={styles.header}>
<Text>this is header</Text>
</View>
);
const styles = StyleSheet.create({
header: {
backgroundColor: 'pink',
alignItems: 'center',
padding: 5,
width: '100%',
},
});
export default Header;
다음과 같이 작성한 후 Header를 export해준다.
App.js에 Header로 export된 것을 import한다.
import Header from './src/header';
헤더에 작성한 코드는 보여지는 것 이므로 View태그 안에 사용해야하며, 다음과 같이 컴포넌트 태그들과 유사하게 사용해준다
App.js
/**
* Sample React Native App
* https://github.com/facebook/react-native
*
* @format
* @flow strict-local
*/
import React, {Component} from 'react';
import {View, Text, StyleSheet} from 'react-native';
import Header from './src/header';
class App extends Component {
render() {
return (
<View style={styles.mainView}>
<Header />
</View>
);
}
}
const styles = StyleSheet.create({
mainView: {
flex: 1,
backgroundColor: 'white',
paddingTop: 50,
alignItems: 'center',
justifyContent: 'center',
},
subView: {
backgroundColor: 'yellow',
marginBottom: 10,
},
anotherSubView: {
flex: 2,
backgroundColor: 'yellow',
marginBottom: 10,
width: '100%',
alignItems: 'center',
justifyContent: 'center',
},
mainText: {
fontSize: 20,
fontWeight: 'normal',
color: 'red',
padding: 20,
},
});
export default App;
참고) 두 함수의 차이
exampleFunciton = () => ( 함수내용 )
* jsx(javascript XML : 자바스크립트 확장 문법)를 return함
exampleFunciton = () => { 함수내용 }
return 되는 jsx 컴포넌트가 존재하지 않음
*javascript XML : 자바스크립트 확장 문법
문자열 태그도 아니지만, HTML문법도 아니며, 태그에 감싸져 변수에 할당되는 것
예시)
const example = <tag>hello world</tag>
State를 사용하여 변형
State를 사용하여, header에서 출력해주는 문구를 바꾸어보도록 한다.
App.js에서 state를 만들어 준 후 이를 props를 이용해 header에서 받아 출력한다.
App.js
state로 앱의 이름을 할당한 후, Header태그에 변수로 넣어준다.
class App extends Component {
state = {
appName: 'My First App',
};
render() {
return (
<View style={styles.mainView}>
<Header name={this.state.appName} />
</View>
);
}
}
header.js
매개변수에 props를 넣어준 후, 이를 이용해 출력문구를 변경해준다.
const Header = props => (
<View style={styles.header}>
<Text>{props.name}</Text>
</View>
);
Header에 this is header라는 문구 대신 앱의 이름이 출력된 것을 확인할 수 있다.
이제 Touch event를 실습해볼 환경구성이 끝났다.
Touch Event
뷰가 터치에 반응하도록 하는 기능
https://reactnative.dev/docs/touchableopacity
TouchableOpacity IMPORT
import {TouchableOpacity} from 'react-native';
기능을 사용하기 위해 import를 해줍니다.
사용예시)
헤더에 터치시 alert가 뜨는 기능을 추가해보았다
/**
* Sample React Native App
* https://github.com/facebook/react-native
*
* @format
* @flow strict-local
*/
import React from 'react';
import {View, Text, StyleSheet, TouchableOpacity} from 'react-native';
//참고 : jsx component를 return하므로 () => (이부분이 소괄호)
const Header = props => (
<TouchableOpacity style={styles.header} onPress={() => alert('hello world')}>
<View style={styles.header}>
<Text>{props.name}</Text>
</View>
</TouchableOpacity>
);
const styles = StyleSheet.create({
header: {
backgroundColor: 'pink',
alignItems: 'center',
padding: 5,
width: '100%',
},
});
export default Header;
결과)
터치전 | 터치시 |
Property
TouchableOpacity가 가진 여러 특성
1. TouchableWithoutFeedbackProps를 상속받음
Touchable Opacity와 같으나 투명해지지(위 화면 오른쪽부분 배경이 약간 투명해진 효과) 않음
예시)
주의할 점은 TouchableWithoutFeedback은 style이 적용되지 않아 styled을 view에 넣어주어야 한다는 사실
import {
View,
Text,
StyleSheet,
TouchableWithoutFeedback,
} from 'react-native';
const Header = props => (
<TouchableWithoutFeedback onPress={() => alert('hello world')}>
<View style={styles.header}>
<Text>{props.name}</Text>
</View>
</TouchableWithoutFeedback>
);
2. 다양하게 사용할 수 있는 함수
onPress 대신 다른 함수를 사용할 수 있다.
이름 | 효과 |
onPress | 터치를 하고 손을 떼었을 때 실행됨 |
onLongPress | 오래 터치하고 있을 때 실행됨 |
onPressIn | 터치를 하자마자 실행됨 |
onPressOut | 터치를 하고 손을 떼었을 때 실행됨(onPress보다 앞서서 실행됨) |
3. Text나 View에도 이를 적용할 수 있음
/**
* Sample React Native App
* https://github.com/facebook/react-native
*
* @format
* @flow strict-local
*/
import React, {Component} from 'react';
import {View, Text, StyleSheet} from 'react-native';
import Header from './src/header';
class App extends Component {
state = {
appName: 'My First App',
};
render() {
return (
<View style={styles.mainView}>
{/* <Header name={this.state.appName} /> */}
<Text style={styles.mainText} onPress={() => alert('touch event')}>
Hello world
</Text>
</View>
);
}
}
const styles = StyleSheet.create({
mainView: {
//생략
mainText: {
fontSize: 20,
fontWeight: 'normal',
color: 'red',
padding: 20,
},
});
export default App;
결과)
터치전 | 터치시 |
Touchevent를 import하지 않아도 되는 모양(?)...
Button
말그대로 버튼을 만들어 보자
Button생성
Button IMPORT
먼저, 버튼을 사용하기 위해서는 react-native에서 임포트해와야한다.
import {Button} from 'react-native'
Button 생성
주의할 점은 버튼을 생성할 때는 title이 필수로 들어가야한다는 점이다.
Button은 View태그 내부에 넣어주어야 한다.
버튼을 따로 관리해주기 위해 generator.js라는 파일을 src하위에 생성해준 후 다음과 같이 작성한다.
/**
* Sample React Native App
* https://github.com/facebook/react-native
*
* @format
* @flow strict-local
*/
import React from 'react';
import {View, Text, StyleSheet, Button} from 'react-native';
const Generator = () => {
return (
<View>
<Button title={'Add Number'} />
</View>
);
};
export default Generator;
App.js에 generator를 import하여 다음과 같이 추가해준다.
/**
* Sample React Native App
* https://github.com/facebook/react-native
*
* @format
* @flow strict-local
*/
import React, {Component} from 'react';
import {View, Text, StyleSheet} from 'react-native';
import Header from './src/header';
import Generator from './src/generator';
class App extends Component {
state = {
appName: 'My First App',
};
render() {
return (
<View style={styles.mainView}>
<Header name={this.state.appName} />
<View>
<Text style={styles.mainText} onPress={() => alert('touch event')}>
Hello world
</Text>
</View>
<Generator />
</View>
);
}
}
const styles = StyleSheet.create({
mainView: {
flex: 1,
backgroundColor: 'white',
paddingTop: 50,
alignItems: 'center',
justifyContent: 'center',
},
subView: {
backgroundColor: 'yellow',
marginBottom: 10,
},
anotherSubView: {
flex: 2,
backgroundColor: 'yellow',
marginBottom: 10,
width: '100%',
alignItems: 'center',
justifyContent: 'center',
},
mainText: {
fontSize: 20,
fontWeight: 'normal',
color: 'red',
padding: 20,
},
});
export default App;
다음과 같이 일단 아무기능없는 버튼이 하나 생성된 것을 볼 수 있다.
참고> ios와 안드로이드는 default 모양이 다르다
Button Style
버튼에 Style을 넣기
Style강의에서 배운대로 styleSheet를 이용한 후 버튼을 감싼 View에 적용한다
/**
* Sample React Native App
* https://github.com/facebook/react-native
*
* @format
* @flow strict-local
*/
import React from 'react';
import {View, Text, StyleSheet, Button} from 'react-native';
const Generator = () => {
return (
<View style={styles.generator}>
<Button title={'Add Number'} />
</View>
);
};
const styles = StyleSheet.create({
generator: {
backgroundColor: '#FFDFB0',
alignItems: 'center',
padding: 5,
width: '100%',
},
});
export default Generator;
Button에 기능 부여
버튼 태그 내에 onPress함수를 이용하여 버튼에 기능을 추가 할 수 있다.
일단 Alert를 추가해본다.
Alert Button
/**
* Sample React Native App
* https://github.com/facebook/react-native
*
* @format
* @flow strict-local
*/
import React from 'react';
import {View, Text, StyleSheet, Button} from 'react-native';
const Generator = () => {
return (
<View style={styles.generator}>
<Button title={'Add Number'} onPress={() => alert('Button pressed!')} />
</View>
);
};
const styles = StyleSheet.create({
generator: {
backgroundColor: '#FFDFB0',
alignItems: 'center',
padding: 5,
width: '100%',
},
});
export default Generator;
+ 기능을 가진 버튼을 만들어 보자!
위에서 배운 것들을 이용하여, 버튼을 누르면 random하게 번호가 생성되어 저장되는 기능을 가진 버튼을 만들어보자
1. 버튼에 의해 생성될 데이터 저장소 (State)
버튼에 의해 random하게 생성된 번호는 App.js에서 관리해야 하므로, App.js에서 State에 이를 관리할 배열을 추가해준다.
App.js
class App extends Component {
state = {
appName: 'My First App',
random: [36, 999],
};
//생략
}
다음과 같이 random이라는 state를 추가한다.
2. 랜덤한 변수를 생성해내는 함수를 생성한다.
일단 자세한 기능을 넣기전 확인용으로 alert를 이용한다.
App.js
onAddRandomNum = () => {
alert('add random Number!');
};
3. (2)에서 만든 함수를 generator에 넘겨준다
class App extends Component {
state = {
appName: 'My First App',
random: [36, 999],
};
onAddRandomNum = () => {
alert('add random Number!');
};
render() {
return (
<View style={styles.mainView}>
//생략
<Generator add={this.onAddRandomNum} />
</View>
);
}
}
Generator에 변수로 제작한 함수를 넘겨준다
4. props를 이용해 받아온 함수를 Button태그에 넣는다.
generator.js
const Generator = props => {
return (
<View style={styles.generator}>
<Button title={'Add Number'} onPress={() => props.add()} />
</View>
);
};
export default Generator;
props를 이용해 전달받은 변수(함수)를 사용한다.
()이거 안넣어주면 실행안됨
이제 버튼을 누르면 alert가 뜬다.
5. random number배열을 보여줄 js파일생성
random number 배열을 보여줄 파일을 따로 관리용으로 생성해준다.
numlist.js
/**
* Sample React Native App
* https://github.com/facebook/react-native
*
* @format
* @flow strict-local
*/
import React from 'react';
import {View, Text, StyleSheet, Button} from 'react-native';
const NumList = props => {
return (
<View style={styles.numlist}>
<Text>{props.num}</Text>
</View>
);
};
const styles = StyleSheet.create({
numlist: {
backgroundColor: '#bebebe',
alignItems: 'center',
padding: 5,
width: '100%',
marginTop: 5,
},
});
export default NumList;
props를 이용해서 App.js가 가진 random배열을 num이라는 변수로 넘겨준다.
(또한, 화면상에서 구분짓기 위해 style에 배경을 회색으로 지정해주었다.->아래에서 확인가능)
App.js
/**
* Sample React Native App
* https://github.com/facebook/react-native
*
* @format
* @flow strict-local
*/
import React, {Component} from 'react';
import {View, Text, StyleSheet} from 'react-native';
import Header from './src/header';
import Generator from './src/generator';
import NumList from './src/numlist';
class App extends Component {
state = {
appName: 'My First App',
random: [36, 999],
};
onAddRandomNum = () => {
alert('add random Number!');
};
render() {
return (
//생략
<NumList num={this.state.random} />
</View>
);
}
}
export default App;
다음과 같이 NumList를 import해온 후에 num이라는 변수에 random이라는 state를 넘겨준다.
이렇게 되면, Generator아래 다음과 같이 화면이 뜨며, 넘겨받은 36과 999가 출력됨을 볼 수 있다.
이를 보면 우리가 원하던 출력형식이 아님을 알 수 있다.
배열을 받아올 때는 배열 객체 내장함수를 사용해주어야 한다.
array.map(item, index)
배열 객체 내장함수
arr.map(a,b)
a는 배열의 value, b는 배열의 index
let arr = [10,20,30,40,50]; let twice = arr.map((v,i)=>{ console.log(`i: ${i}, v: ${v}`) }); console.log(twice); //결과 i: 0, v: 10 i: 1, v: 20 i: 2, v: 30 i: 3, v: 40 i: 4, v: 50
이전글 참고
https://iagreebut.tistory.com/124
ES6문법
즉, numList에서 random배열을 받아왔을 때 다음과 같이 수정해주어야 한다.
numlist.js
/**
* Sample React Native App
* https://github.com/facebook/react-native
*
* @format
* @flow strict-local
*/
import React from 'react';
import {View, Text, StyleSheet, Button} from 'react-native';
const NumList = props => {
return props.num.map((item, idx) => (
<View style={styles.numlist}>
<Text>{item}</Text>
</View>
));
};
const styles = StyleSheet.create({
numlist: {
backgroundColor: '#bebebe',
alignItems: 'center',
padding: 5,
width: '100%',
marginTop: 5,
},
});
export default NumList;
이제 각각이 따로 잘 출력되는 것을 볼 수 있다.
6. 함수에 기능부여
App.js에서 임시로 alert를 넣었던 함수내에 난수를 생성하여 state값에 추가시기도록 변경해본다.
App.js
onAddRandomNum = () => {
const randomNum = Math.floor(Math.random() * 100) + 1;
this.setState(prevState => {
return {
random: [...prevState.random, randomNum],
};
});
};
Math.random()함수를 이용하여 1~100까지의 난수를 발생시켜 randomNum이라는 변수에 저장한 뒤,
setState를 이용하여, 이전 state(prevState)를 받아와 반영한 뒤, 그 뒤에 생성된 새로운 변수를 추가하여 return해준다.
Add Number라는 버튼을 누를 떄 마다 새로운 수가 생성되어 리스트에 반영되어 화면에 출력되는 모습을 볼 수 있다.
TouchEvent기능부여
이제 추가적으로 "숫자"를 클릭하면, 숫자가 사라지도록 한다.
숫자가 쓰여진 곳은 View 태그와 Text태그로 이루어졌으며, 이를 터치시 사라지는 이벤트가 발생해야하므로,
TouchEvent를 활용해준다
1. 숫자의 View tag를 TouchableOpacity로 변경
numlist.js
import React from 'react';
import {View, Text, StyleSheet, TouchableOpacity} from 'react-native';
const NumList = props => {
return props.num.map((item, idx) => (
<TouchableOpacity
style={styles.numlist}
key={idx}
>
<Text>{item}</Text>
</TouchableOpacity>
));
};
export default NumList;
TouchableOpacity를 import한 후, View태그를 변경해준다.
2. Delete기능을 하는 함수를 생성하여 연결
일단 위와 마찬가지로 임시로 alert를 띄우는 함수를 작성하여 변수를 이용해 numlist로 넘겨준다
App.js
class App extends Component {
state = {
appName: 'My First App',
random: [36, 999],
};
//생략
onDeleteNum = () => {
alert('delete num');
};
render() {
return (
<View style={styles.mainView}>
//생략
<NumList num={this.state.random} delete={this.onDeleteNum} />
</View>
);
}
}
export default App;
delete라는 변수명으로 onDeleteNum함수를 넘겨준다.
이를 numlist에서 props를 이용해 반영해준다.
numlist.js
import React from 'react';
import {View, Text, StyleSheet, TouchableOpacity} from 'react-native';
const NumList = props => {
return props.num.map((item, idx) => (
<TouchableOpacity
style={styles.numlist}
key={idx}
onPress={() => props.delete()}>
<Text>{item}</Text>
</TouchableOpacity>
));
};
export default NumList;
3. Delete작용을 하도록 함수 작성
일단 삭제를 진행하기 위해, 터치된 숫자의 index를 알아야하므로,
onDeleteNum의 변수로 index를 주어줌
numlist.js
const NumList = props => {
return props.num.map((item, idx) => (
<TouchableOpacity
style={styles.numlist}
key={idx}
onPress={() => props.delete(idx)}>
<Text>{item}</Text>
</TouchableOpacity>
));
};
일단 numlist에서 index를 보유하고 있으므로, 해당 index를 가리키는 변수인 idx를
delete의 매개변수로 넣는다.
App.js에서 선언된 onDeleteNum에도 적용해준다. position이라는 변수에 저장한다.
App.js
onDeleteNum = position => {
alert('delete num');
};
이제 새로운 array를 생성하여 거기에 원하는 인덱스가 제거된 배열을 만들고 이를 state로 업데이트 시켜주는 방식사용
onDeleteNum = position => {
const newArray = this.state.random.filter((num, index) => {
return position != index;
});
};
배열 내장함수 filter를 사용 : 특정조건에 부합되는 요소들만 뽑아내 새 배열을 만들어내는 함수
포지션과 인덱스가 일치하지 않는 것들로만 모아 새 배열을 만듬 ( 포지션과 인덱스와 일치하는 것은 없음 -> 제거와 같은 효과)
이때 , num 과 index를 return하기 때문에, num을 사용하지 않아도 선언해주어야 한다.
setState를 이용하여 새로 만든 array로 변경해준다.
onDeleteNum = position => {
const newArray = this.state.random.filter((num, index) => {
return position != index;
});
this.setState({random: newArray});
};
결과)
13 클릭 이전 | 13 클릭 이후 |
다음과 같이 숫자를 클릭하면 사라지는 것을 볼 수 있다.
전체코드)
App.js
/**
* Sample React Native App
* https://github.com/facebook/react-native
*
* @format
* @flow strict-local
*/
import React, {Component} from 'react';
import {View, Text, StyleSheet} from 'react-native';
import Header from './src/header';
import Generator from './src/generator';
import NumList from './src/numlist';
class App extends Component {
state = {
appName: 'My First App',
random: [36, 999],
};
onAddRandomNum = () => {
const randomNum = Math.floor(Math.random() * 100) + 1;
this.setState(prevState => {
return {
random: [...prevState.random, randomNum],
};
});
};
onDeleteNum = position => {
const newArray = this.state.random.filter((num, index) => {
return position != index;
});
this.setState({random: newArray});
};
render() {
return (
<View style={styles.mainView}>
<Header name={this.state.appName} />
<View>
<Text style={styles.mainText} onPress={() => alert('touch event')}>
Hello world
</Text>
</View>
<Generator add={this.onAddRandomNum} />
<NumList num={this.state.random} delete={this.onDeleteNum} />
</View>
);
}
}
const styles = StyleSheet.create({
mainView: {
flex: 1,
backgroundColor: 'white',
paddingTop: 50,
alignItems: 'center',
//justifyContent: 'center',
},
subView: {
backgroundColor: 'yellow',
marginBottom: 10,
},
anotherSubView: {
flex: 2,
backgroundColor: 'yellow',
marginBottom: 10,
width: '100%',
alignItems: 'center',
justifyContent: 'center',
},
mainText: {
fontSize: 20,
fontWeight: 'normal',
color: 'red',
padding: 20,
},
});
export default App;
numlist.js
/**
* Sample React Native App
* https://github.com/facebook/react-native
*
* @format
* @flow strict-local
*/
import React from 'react';
import {View, Text, StyleSheet, TouchableOpacity} from 'react-native';
const NumList = props => {
return props.num.map((item, idx) => (
<TouchableOpacity
style={styles.numlist}
key={idx}
onPress={() => props.delete(idx)}>
<Text>{item}</Text>
</TouchableOpacity>
));
};
const styles = StyleSheet.create({
numlist: {
backgroundColor: '#bebebe',
alignItems: 'center',
padding: 5,
width: '100%',
marginTop: 5,
},
});
export default NumList;
generator.js
/**
* Sample React Native App
* https://github.com/facebook/react-native
*
* @format
* @flow strict-local
*/
import React from 'react';
import {View, Text, StyleSheet, Button} from 'react-native';
const Generator = props => {
return (
<View style={styles.generator}>
<Button title={'Add Number'} onPress={() => props.add()} />
</View>
);
};
const styles = StyleSheet.create({
generator: {
backgroundColor: '#FFDFB0',
alignItems: 'center',
padding: 5,
width: '100%',
},
});
export default Generator;
header.js
/**
* Sample React Native App
* https://github.com/facebook/react-native
*
* @format
* @flow strict-local
*/
import React from 'react';
import {
View,
Text,
StyleSheet,
TouchableOpacity,
TouchableWithoutFeedback,
} from 'react-native';
//참고 : jsx component를 return하므로 () => (이부분이 소괄호)
//"TouchableOpacity"
const Header = props => (
<TouchableOpacity
style={styles.header}
onPress={() => alert('On Press')}
//onLongPress={() => alert('on long press')}
//onPressIn={() => alert('on press in')}
//onPressOut={() => alert('on press out')}
>
<View style={styles.header}>
<Text>{props.name}</Text>
</View>
</TouchableOpacity>
);
//"TouchableWithoutFeedback"
// const Header = props => (
// <TouchableWithoutFeedback onPress={() => alert('hello world')}>
// <View style={styles.header}>
// <Text>{props.name}</Text>
// </View>
// </TouchableWithoutFeedback>
// );
const styles = StyleSheet.create({
header: {
backgroundColor: 'pink',
alignItems: 'center',
padding: 5,
width: '100%',
},
});
export default Header;