Learning React(5. React 이벤트 다루기)
1. 이벤트
01. 시작 전 준비
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>React!</title>
<!-- 리액트 라이브러리와 리액트가 DOM에 대한 작업할 때 필요한 다양한 기능을 추가 -->
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<!-- 바벨, 자바스크립트 컴파일러의 참조 -->
<script src="https://unpkg.com/[email protected]/babel.min.js"></script>
<style>
#container {
padding: 50px;
background-color: #EEE;
}
</style>
</head>
<body>
<div id="container"></div>
<script type="text/babel">
var destination = document.querySelector("#container");
</script>
</body>
</html>
02. UI 구현
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>React!</title>
<!-- 리액트 라이브러리와 리액트가 DOM에 대한 작업할 때 필요한 다양한 기능을 추가 -->
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<!-- 바벨, 자바스크립트 컴파일러의 참조 -->
<script src="https://unpkg.com/[email protected]/babel.min.js"></script>
<style>
#container {
padding: 50px;
background-color: #EEE;
}
</style>
</head>
<body>
<div id="container"></div>
<script type="text/babel">
class Counter extends React.Component {
render() {
var textStyle = {
fontSize : 78,
fontFmail : 'sans-serif',
color : '#333',
fontWeight : 'bold'
};
return(
<div style={textStyle}>
{this.props.display}
</div>
)
}
}
class CounterParent extends React.Component {
constructor(props) {
super(props);
this.state = {
count : 0
};
}
render() {
var backgroundStyle = {
padding : 50,
backgroundColor : '#FFC53A',
width : 250,
height : 100,
borderRadius : 10,
textAlign : 'center'
};
var buttonStyle = {
fontSize : '1em',
width : 30,
height : 30,
fontFmail : 'sans-serif',
color : '#333',
fontWeight : 'bold',
lineHeight : '3px'
};
return (
<div style={backgroundStyle}>
<Counter display={this.state.count} />
<button style={buttonStyle}>+</button>
</div>
);
}
}
ReactDOM.render(
<div>
<CounterParent/>
</div>,
document.querySelector("#container")
)
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>React!</title>
<!-- 리액트 라이브러리와 리액트가 DOM에 대한 작업할 때 필요한 다양한 기능을 추가 -->
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<!-- 바벨, 자바스크립트 컴파일러의 참조 -->
<script src="https://unpkg.com/[email protected]/babel.min.js"></script>
<style>
#container {
padding: 50px;
background-color: #EEE;
}
</style>
</head>
<body>
<div id="container"></div>
<script type="text/babel">
var destination = document.querySelector("#container");
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>React!</title>
<!-- 리액트 라이브러리와 리액트가 DOM에 대한 작업할 때 필요한 다양한 기능을 추가 -->
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<!-- 바벨, 자바스크립트 컴파일러의 참조 -->
<script src="https://unpkg.com/[email protected]/babel.min.js"></script>
<style>
#container {
padding: 50px;
background-color: #EEE;
}
</style>
</head>
<body>
<div id="container"></div>
<script type="text/babel">
class Counter extends React.Component {
render() {
var textStyle = {
fontSize : 78,
fontFmail : 'sans-serif',
color : '#333',
fontWeight : 'bold'
};
return(
<div style={textStyle}>
{this.props.display}
</div>
)
}
}
class CounterParent extends React.Component {
constructor(props) {
super(props);
this.state = {
count : 0
};
}
render() {
var backgroundStyle = {
padding : 50,
backgroundColor : '#FFC53A',
width : 250,
height : 100,
borderRadius : 10,
textAlign : 'center'
};
var buttonStyle = {
fontSize : '1em',
width : 30,
height : 30,
fontFmail : 'sans-serif',
color : '#333',
fontWeight : 'bold',
lineHeight : '3px'
};
return (
<div style={backgroundStyle}>
<Counter display={this.state.count} />
<button style={buttonStyle}>+</button>
</div>
);
}
}
ReactDOM.render(
<div>
<CounterParent/>
</div>,
document.querySelector("#container")
)
</script>
</body>
</html>
03. 버튼 기능 구현
- 버튼 클릭 이벤트 리스너를 등록
- 클릭할 때마다 this.state.count 속성의 값을 증가시키는 핸들러를 구현한다
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>React!</title>
<!-- 리액트 라이브러리와 리액트가 DOM에 대한 작업할 때 필요한 다양한 기능을 추가 -->
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<!-- 바벨, 자바스크립트 컴파일러의 참조 -->
<script src="https://unpkg.com/[email protected]/babel.min.js"></script>
<style>
#container {
padding: 50px;
background-color: #EEE;
}
</style>
</head>
<body>
<div id="container"></div>
<script type="text/babel">
class Counter extends React.Component {
render() {
var textStyle = {
fontSize : 78,
fontFmail : 'sans-serif',
color : '#333',
fontWeight : 'bold'
};
return(
<div style={textStyle}>
{this.props.display}
</div>
)
}
}
class CounterParent extends React.Component {
constructor(props) {
super(props);
this.state = {
count : 0
};
this.increas = this.increas.bind(this);
}
increas(e) {
this.setState({
count : this.state.count + 1
})
}
render() {
var backgroundStyle = {
padding : 50,
backgroundColor : '#FFC53A',
width : 250,
height : 100,
borderRadius : 10,
textAlign : 'center'
};
var buttonStyle = {
fontSize : '1em',
width : 30,
height : 30,
fontFmail : 'sans-serif',
color : '#333',
fontWeight : 'bold',
lineHeight : '3px'
};
return (
<div style={backgroundStyle}>
<Counter display={this.state.count} />
<button onClick={this.increas} style={buttonStyle}>+</button>
</div>
);
}
}
ReactDOM.render(
<div>
<CounterParent/>
</div>,
document.querySelector("#container")
)
</script>
</body>
</html>
04. 합성 이벤트(Synthetic Event)
- MouseEvent나 KeyboardEvent 등과 같은 네이티브 이벤트를 받지 않으며, 항상 브라우저의 네이티브 이벤트를 래핑하는 SyntheticEvent 타입을 인자로 받는다
- Synthetic Event를 가지고도 평범하게 DOM에서 했던 작업을 할 수 있다
-1. Synthetic Event 속성
- boolean bubbles
- boolean cancelable
- DOMEventTarget currentTarget
- boolean defaultPrevented
- number eventPhase
- boolean isTrusted
- DOMEvent nativeEvent
- void preventDefault()
- boolean isDefaultPrevented()
- void stopPropagation()
- boolean isPropagationStopped()
- DOMEventTarget target
- number timeStamp
- string type
-2. Mouse Synthetic Event 속성
- boolean altKey
- number button
- number buttons
- number clientX
- number clientY
- boolean ctrlKey
- boolean getModifierState(key)
- booelan metaKey
- number pageX
- number pageY
- DOMEventTarget relatedTarget
- number screenX
- number screenY
- boolean shiftKey
-3. Keyboard Synthetic Event 속성
- boolean altKey
- number charCode
- boolean ctrlKey
- boolean getModifierState(key)
- string key
- number keyCode
- string locale
- number location
- boolean metaKey
- boolean repeat
- boolean shiftKey
- number whitch
05. 이벤트 속성 활용하기
- 이전 작업에서 추가로 shift키를 누른채로 플러스 버튼을 클릭하면 카운터가 10씩 증가하게 이벤트를 추가한다(boolean shiftKey)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>React!</title>
<!-- 리액트 라이브러리와 리액트가 DOM에 대한 작업할 때 필요한 다양한 기능을 추가 -->
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<!-- 바벨, 자바스크립트 컴파일러의 참조 -->
<script src="https://unpkg.com/[email protected]/babel.min.js"></script>
<style>
#container {
padding: 50px;
background-color: #EEE;
}
</style>
</head>
<body>
<div id="container"></div>
<script type="text/babel">
class Counter extends React.Component {
render() {
var textStyle = {
fontSize : 78,
fontFmail : 'sans-serif',
color : '#333',
fontWeight : 'bold'
};
return(
<div style={textStyle}>
{this.props.display}
</div>
)
}
}
class CounterParent extends React.Component {
constructor(props) {
super(props);
this.state = {
count : 0
};
this.increas = this.increas.bind(this);
}
increas(e) {
var currentCount = this.state.count;
currentCount = (e.shiftKey)? currentCount+=10 : currentCount+=1;
this.setState({
count : currentCount
})
}
render() {
var backgroundStyle = {
padding : 50,
backgroundColor : '#FFC53A',
width : 250,
height : 100,
borderRadius : 10,
textAlign : 'center'
};
var buttonStyle = {
fontSize : '1em',
width : 30,
height : 30,
fontFmail : 'sans-serif',
color : '#333',
fontWeight : 'bold',
lineHeight : '3px'
};
return (
<div style={backgroundStyle}>
<Counter display={this.state.count} />
<button onClick={this.increas} style={buttonStyle}>+</button>
</div>
);
}
}
ReactDOM.render(
<div>
<CounterParent/>
</div>,
document.querySelector("#container")
)
</script>
</body>
</html>
06. 다른 이벤트 처리 기법
-1. 컴포넌트의 이벤트는 직접 리스닝할 수 없다
_1. 컴포넌트에 직접 이벤트 전달
- 컴포넌트는 DOM 엘리먼트를 감싸는 래퍼이기 때문에 컴포넌트는 이벤트를 직접 리스닝 할수는 없다
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>React!</title>
<!-- 리액트 라이브러리와 리액트가 DOM에 대한 작업할 때 필요한 다양한 기능을 추가 -->
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<!-- 바벨, 자바스크립트 컴파일러의 참조 -->
<script src="https://unpkg.com/[email protected]/babel.min.js"></script>
<style>
#container {
padding: 50px;
background-color: #EEE;
}
</style>
</head>
<body>
<div id="container"></div>
<script type="text/babel">
class Counter extends React.Component {
render() {
var textStyle = {
fontSize : 78,
fontFmail : 'sans-serif',
color : '#333',
fontWeight : 'bold'
};
return(
<div style={textStyle}>
{this.props.display}
</div>
)
}
}
class PlusButton extends React.Component {
render () {
var buttonStyle = {
fontSize : '1em',
width : 30,
height : 30,
fontFmail : 'sans-serif',
color : '#333',
fontWeight : 'bold',
lineHeight : '3px'
};
return(
<button style={buttonStyle}> + </button>
)
}
}
class CounterParent extends React.Component {
constructor(props) {
super(props);
this.state = {
count : 0
};
this.increas = this.increas.bind(this);
}
increas(e) {
var currentCount = this.state.count;
currentCount = (e.shiftKey)? currentCount+=10 : currentCount+=1;
this.setState({
count : currentCount
})
}
render() {
var backgroundStyle = {
padding : 50,
backgroundColor : '#FFC53A',
width : 250,
height : 100,
borderRadius : 10,
textAlign : 'center'
};
return (
<div style={backgroundStyle}>
<Counter display={this.state.count} />
<PlusButton onClick={this.increas}/>
</div>
);
}
}
ReactDOM.render(
<div>
<CounterParent/>
</div>,
document.querySelector("#container")
)
</script>
</body>
</html>
_2. 컴포넌트 내부의 DOM 엘리먼트에 이벤트 속성 전달
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>React!</title>
<!-- 리액트 라이브러리와 리액트가 DOM에 대한 작업할 때 필요한 다양한 기능을 추가 -->
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<!-- 바벨, 자바스크립트 컴파일러의 참조 -->
<script src="https://unpkg.com/[email protected]/babel.min.js"></script>
<style>
#container {
padding: 50px;
background-color: #EEE;
}
</style>
</head>
<body>
<div id="container"></div>
<script type="text/babel">
class Counter extends React.Component {
render() {
var textStyle = {
fontSize : 78,
fontFmail : 'sans-serif',
color : '#333',
fontWeight : 'bold'
};
return(
<div style={textStyle}>
{this.props.display}
</div>
)
}
}
class PlusButton extends React.Component {
render () {
var buttonStyle = {
fontSize : '1em',
width : 30,
height : 30,
fontFmail : 'sans-serif',
color : '#333',
fontWeight : 'bold',
lineHeight : '3px'
};
return(
<button onClick={this.props.clickHandler} style={buttonStyle}> + </button>
)
}
}
class CounterParent extends React.Component {
constructor(props) {
super(props);
this.state = {
count : 0
};
this.increas = this.increas.bind(this);
}
increas(e) {
var currentCount = this.state.count;
currentCount = (e.shiftKey)? currentCount+=10 : currentCount+=1;
this.setState({
count : currentCount
})
}
render() {
var backgroundStyle = {
padding : 50,
backgroundColor : '#FFC53A',
width : 250,
height : 100,
borderRadius : 10,
textAlign : 'center'
};
return (
<div style={backgroundStyle}>
<Counter display={this.state.count} />
<PlusButton clickHandler={this.increas}/>
</div>
);
}
}
ReactDOM.render(
<div>
<CounterParent/>
</div>,
document.querySelector("#container")
)
</script>
</body>
</html>
07. 이벤트 핸들러 내부의 this
function doSomething(e) {
console.log(this); // button element
}
var btn = document.querySelector("button");
btn.addEventListener('click', doSomething, false);
- 이벤트 핸들러 내부의 this는 이벤트를 발생시킨 엘리먼트를 참조한다 하지만 react에서 this는 이벤트를 발생시킨 엘리먼트의 참조가 아니다
- 그 값은 도움이 안되는 그냥 undefined다, 지금까지 여러번 봤듯 bind 메서드를 사용해 this를 명시적으로 지정해야 하는 이유가 이 때문이다
this.increas = this.increas.bind(this);
- 여기서 increas 이벤트 핸들러 안의 this는 이벤트를 촉발시킨 엘리먼트가 아닌 CounterParent 컴포넌트를 참조한다
- 이는 생성자 안에서 this의 값을 컴포넌트에 바인딩 시켰기 때문이다
08. 리액트에서의 이벤트 처리는... 도대체 왜?
-1. 브라우저 호환성
- 오늘날 브라우저 사이에서 일관되게 작동하는 기능 중 하나지만 예전 브라우저 환경으로 돌아가면 상환은 급격히 악화된다
- 이 문제를 해결하기 위해 리액트는 모든 네이티브 이벤트를 SyntheticEvent 타입의 객체로 래핑함으로써, 호환되지 않는 환경에서도 이벤트 처리를 동일한 방법으로 할 수 있게 한다
-2. 성능 향상
- 복잡한 UI를 갖는 앱에서 더 맘ㄶ은 이벤트 핸들러를 만들수록 앱은 더 ㅏㅁㄴ흥 메모리를 차지하게 된다
- 이를 수동으로 조치하는 일은 어렵지 않으나 지루한 일이 될 수 있으며, 때에 따라 불가능할 수도 있다, 그리고 그런 번거로움으로 득보다 실이 더 클 수도 있다, 리액트는 이 부분을 현명하게 대처 했다
- 리액트는 절대 이벤트 핸들러를 DOM 엘리먼트에 직접 부착하지 않는다
- 리액트는 문서 최상위에 있는 하나의 이벤트 핸들러를 사용한다
- 이 이벤트 핸들러는 그 모든 이벤트를 리스닝하며, 이벤트 발생 시 적합한 개별 핸들러를 호출하는 책임을 진다
- 이는 이벤트 처리 코드를 우리가 직접 최적화하지 않아도 되게 해준다
Author And Source
이 문제에 관하여(Learning React(5. React 이벤트 다루기)), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@ansalstmd/Learning-React5.-React-이벤트-다루기저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)