리액트 교과서 Chapter06(React에서 이벤트 다루기)
이벤트 등록을 하는 방법
함수에 현재 컴포넌트를 bind 해주어야한다.
해당 바인드를 하지 않는 경우는 아래와 같다.
- 함수에서 Component 인스턴스를 사용하지 않을 때
- Arrow 함수를 사용 할 때
class HelloWorld extends React.Component {
constructor(prop) {
super(prop)
this.state = {
count : 0
}
// 바인드 방식 1
this.minusBtn = this.minusBtn.bind(this)
}
plusBtn (event) {
this.setState({
count: ++this.state.count
})
}
minusBtn (event) {
this.setState({
count: --this.state.count
})
}
render() {
return (
<div>
<span>{this.state.count}</span>
// 바인드 방식 2
<button onClick={this.plusBtn.bind(this)} >+</button>
<button onClick={this.minusBtn} >-</button>
<button onClick={(event) => {
this.setState({
count: 0
})
}} >clear</button>
</div>
)
}
}
합성이벤트
minusBtn (event)함수에서 event가 합성이벤트이다.
event는 표준화를 위한 React 객체다.
내부 프로퍼티 및 함수는 아래와 같다.
- currentTarget: 이벤트를 캡쳐한 요소의 DOMEventTarget(대상 요소 및 부모요소)
- target: DOMEventTarget가 발생한 요소
- preventDefault(): 링크 나 폼 전송 등 기본 동작을 방지하는 메소드
- isDefaultPrevented(): 기본동작이 방지 되었을 때 True를 반환
- stopPropagation(): 이벤트 전파 중단
- isPropagationStopped: 이벤트 전파가 중단되었다면 true 반환
- type: 태그명 문자열
- persist(): 합성 이벤트를 이벤트 풀에서 꺼낸 후 사용자 코드에서 이벤트에 대한 참조를 유지할 수 있도록 한다.
- isPersistent(): 합성 이벤트를 이벤트 풀에서 꺼낸경우 true를 반환
입력이 된 텍스트 상자의 value를 가져오는 방법
...
getNameInputValue(event) {
console.log(e.target.value)
}
...
컴포넌트간 통신
컴포넌트간 데이터의 변경을 주고 받아야 한다면 부모 컴포넌트에서 상태를 관리하고 하위에는 변경에 대한 메소드
변경된 값들을 전달하는 것이 좋은 패턴이다.
- parent -> content로 상태 전달
- parent -> btn으로 함수전달
- btn -> parent 함수 호출
- parent -> content 변경된 상태 전달
class Parent extends React.Component {
constructor(prop) {
super(prop)
this.state = {
counter: 0
}
}
updateCounter(e) {
console.log('wow')
this.setState({counter : ++this.state.counter})
}
render() {
return <div>
<ChildContent counter={this.state.counter}></ChildContent>
<ChildBtn updateCounter={this.updateCounter.bind(this)}></ChildBtn>
</div>
}
}
class ChildContent extends React.Component {
render() {
return <span>{this.props.counter}</span>
}
}
class ChildBtn extends React.Component {
render() {
console.log(this.props)
return <button onClick={this.props.updateCounter}>+</button>
}
}
React가 지원하지 않는 이벤트 처리
resize 이벤트는 React에서 지원하지 않는다.
이를 해결하기 위해 라이프 사이클 메소드를 사용한다.
// 동작하지 않음
return <div onResize={this.handleResize}></div>
동작
- window에 이벤트 리스너 등록
- 화면의 크기가 변동되면 상태 갱신
- 상태 갱신으로 인한 동적 style 갱신
class Radio extends React.Component {
constructor(prop) {
super(prop)
this.handleResize = this.handleResize.bind(this)
let i = 1
this.state = {
outerStyle: this.getStyle(4, i),
innerStyle: this.getStyle(1, i),
selectedStyle: this.getStyle(2, i),
taggerStyle: {top: 20, width: 25, height: 25}
}
}
getStyle (i, m){
let value = i * m
return { top: value, bottom: value, left: value, right: value}
}
componentDidMount() {
window.addEventListener('resize', this.handleResize)
}
componentWillUnmount() {
window.removeEventListener('resize', this.handleResize)
}
handleResize() {
let w = 1+ Math.round(window.innerWidth / 300)
this.setState({
taggerStyle: {top: w*10, width : w*10, height: w*10 },
textStyle: {left: w*13, fontSize: 7*w}
})
}
render() {
return <div>
<div className="radio-tagger" style={this.state.taggerStyle}>
<input type="radio" name={this.props.name} id={this.props.id} />
<label htmlFor={this.props.id}>
<div className="radio-text" style={this.state.textStyle}>{this.props.label}</div>
<div className="radio-outer" style={this.state.outerStyle}>
<div className="radio-inner" style={this.state.innerStyle}>
<div className="radio-selected" style={this.state.selectedStyle}></div>
</div>
</div>
</label>
</div>
</div>
}
}