React

생활코딩 React 강의 (6) - 이벤트

joy_lee 2021. 9. 6. 17:32

이벤트

props, state, event 삼자가 상호작용하며 애플리케이션의 역동성을 만든다.

우리가 만들고 싶은 이벤트는 list 목록을 클릭했을 때, 아래의 내용이 바뀌는 것을 목표로 한다.

그러면 아래와 같은 과정을 거쳐야 한다.

링크 클릭→app 컴포넌트의 state 변화→Content 컴포넌트의 props값으로 전달→애플리케이션 동적으로 바뀜

 

React에서는 state/props의 값이 바뀌면 그 state를 가지고 있는 컴포넌트의 render()함수가 다시 호출된다.

그러면 상위 컴포넌트 안에 속한 하위 컴포넌트의 render() 함수들도 다시 호출되고, 화면이 다시 그려진다.

console.log로 각 컴포넌트의 render() 함수가 호출될 때 마다 확인메시지를 띄워보았다.

첫 가동시에 App, Subject, TOC, Content가 순서대로 호출되었다. App의 state에서 mode:"welcome"에서 "read"로 바꿔주니 다시 App이 호출되고, 하위 컴포넌트들이 차례로 호출되는 것을 확인할 수 있다.

 

그리고 App의 mode에 따라 다른 정보를 전달하도록 코드를 작성한다.

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
32
33
34
35
36
class App extends Component {
  constructor(props){
    super(props);
    this.state = {
      mode: "welcome",
      subject:{title:"WEB", sub:"world wide web!"},
      welcome:{title:"Welcome", desc:"Hello, React!"},
      contents:[
        {id:1, title:"HTML", desc:"HTML is for information"},
        {id:2, title:"CSS", desc:"CSS is for design"},
        {id:3, title:"Javascript", desc:"Javascript is for interactive"}
      ]
    }    
  }
  render() {
    console.log("App render")
    var _title, _desc = null;
    if(this.state.mode === "welcome"){
      _title = this.state.welcome.title;
      _desc = this.state.welcome.desc;
    } else if (this.state.mode === "read") {
      _title = this.state.contents[0].title;
      _desc = this.state.contents[0].desc;
    }
    return (
      <div className="App">
        <Subject 
          title={this.state.subject.title}
          sub={this.state.subject.sub}>
          </Subject>
        <TOC data={this.state.contents}></TOC>
        <Content title={_title} desc={_desc}></Content>
      </div>
    );
  }
}
cs

render()에서 return 윗쪽에 코드를 작성한다.

this.state.mode의 값에 따라 _title과 _desc의 값이 달라지도록 만든 것이다. 이 코드 때문에 render()가 실행될 때 마다 mode를 확인해 다른 값을 Content에 전달할 수 있게 된다.

 

이벤트 설치

Subject의 a 태그를 클릭하면 이벤트가 실행되도록 하려고 한다.

일단 subject 컴포넌트를 사용하지 않고 app에서 직접 이벤트를 설치하기 위해 잠시 subject컴포넌트의 내용을 app으로 옮긴다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class App extends Component {
  render() {
    return (
      <div className="App">
        {/* <Subject 
          title={this.state.subject.title}
          sub={this.state.subject.sub}>
          </Subject> */}
        <header>
          <h1><a href="/" onClick={function(e){
            console.log(e);
            e.preventDefault();
          }}>{this.state.subject.title}</a></h1>
          {this.state.subject.sub}
        </header>
      </div>
    );
  }
}
cs

 

App에서 나머지 부분은 생략하고 이벤트에 관련된 것만 옮겨온 코드이다.

a태그에 href말고 onClick이라는 속성이 있다. 이 속성을 통해 이벤트를 설치한다.

html에서는 onclick으로 사용하지만 react에서는 onClick으로 사용해줘야 한다.

 

onClick속성에 익명함수를 만들어준다. 이벤트가 실행될 때마다(클릭할 때마다) 호출되는 함수는 첫 번째 변수의 값으로 event라고 하는 객체를 주입해주기로 약속된 함수이다.

(일반적인 html-javascript에서 eventTarget.addEventListener(type, eventListener)에서 listener함수는 기본적으로 event를 인자로 받는 것을 떠올리면 된다.

참고: https://developer.mozilla.org/ko/docs/Web/API/EventTarget/addEventListener#the_event_listener_callback)

익명함수 안에 console.log(e); debugger;만 작성한 후 h1을 클릭하면 다음과 같이 실행된다.

그런데 a가 클릭되어 이벤트가 실행될 때마다 페이지가 새로고침된다. 이것은 a태그의 기본적인 속성이다.(다른 페이지로 이동하기 위함)

하지만 우리가 원하는 것은 새로고침을 하지 않고 내용을 바꾸는 것이기 때문에 익명함수 안에 아래의 코드를 작성해줘야 한다.

e.preventDefault();

기본적인 기능을 막는 함수이다.

 

아래 실행 화면에서 콘솔창을 보면 e.preventDefault()를 통해 기본적인 동작을 막고, 클릭한 것만 확인할 수 있다.

html의 태그에 이벤트를 걸 때 기본적인 동작을 막기 위해 필요한 코드이다.

 

이벤트에서 State 변경하기

onClick을 통해 연결된 이벤트를 처리하는 함수 내에서 state를 바꾸려면 어떻게 해야할까?

가장 간단해보이는 방법은 직접 값을 바꿔주는 것이다.

1
2
3
4
<a href="/" onClick={function(e){
            e.preventDefault();
            this.state.mode = "welcome"// 페이지가 바뀌지 않음!
          }}>{this.state.subject.title}</a>
cs

하지만 이 코드로는 화면의 내용을 바꿀 수 없다.

바꿀 수 없는 두 가지 이유가 있다.

 

이벤트에서 State 변경하기 - 1. this

console.log("onClick", this)를 통해 함수 내의 this를 확인해보면 다음과 같이 나온다.

this는 undefined라는 것이다.

우리가 this를 사용할 때 어떤 객체 안에서 함수를 생성해 호출하면, 자연스럽게 this가 연결될 것이라는 생각을 한다.

컴포넌트 안에서 this를 확인해보면 App으로 나온다. 하지만 함수에는 연결되지 않는다.

아래의 설명을 보면, 대부분의 경우 this는 손실된다고 한다.

출처: https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Function/bind

this를 지정해주기 위한 방법으로 bind()를 소개하고 있다.

이 함수를 사용해 우리가 만든 onClick의 익명함수도 this를 render()가 실행되는 해당 컴포넌트로 지정할 수 있다.

1
2
3
4
<a href="/" onClick={function(e){
            e.preventDefault();
            this.state.mode = "welcome"// 그래도 페이지가 바뀌지 않음!
          }.bind(this)}>{this.state.subject.title}</a>
cs

bind전/후의 this를 확인해보면 분명히 연결되어 있는 것을 확인할 수 있다.(App의 this는 render()안에서 console.log("App", this);로 확인함)

하지만 이렇게 해도 페이지의 내용은 바뀌지 않는다.

 

이벤트에서 State 변경하기 - 2. setState()

State를 변경하기 위해서는 react가 어떻게 state를 관리하는지 알아야 한다.

 

State는 Component안의 Constructor()/생성자함수 가 호출될 때 생성된다. 생성자 함수 안에서는 this.state.mode = "welcome"; 으로 바로 바꿔줄 수 있다. 하지만 이미 컴포넌트가 생성된 후 동적으로 state를 바꿀 때에는 불가능한 방법이다. 왜냐하면 이런 방법으로 바꾸는 경우에는 react가 state가 변경되었는지 알 수 없기 때문에 render()를 실행하지 않는다.

(state 변화) -x-> render() 실행 -> 애플리케이션 동적 변화
다음 단계로 나아가지 못한다

 

.bind(this) 를 해준 뒤 함수 내부에서 console.log(this.state.mode)로 state를 확인해보았다.

state를 직접 변화시키지 말라는 경고 메시지가 출력된다.

console.log(this.state.mode) 를 통해 console에 출력된 결과는 welcome이다. 하지만 페이지의 내용은 갱신되지 않는다.

 

react에서는 state를 변화시키기 위해 setState() 함수를 사용하도록 안내하고 있다.

this.setState({ mode:"welcome" });

setState함수 안에 바꾸고 싶은 값을 객체 형태로 전달해주면 된다.

 

최종적으로 이벤트를 통해 state를 바꾸기 위해서는 아래와 같이 이벤트 함수를 만들면 된다.

1
2
3
4
5
6
<a href="/" onClick={function(e){
            e.preventDefault();
            this.setState({
                mode:"welcome"
            })
          }.bind(this)}>
cs

 

참고한 페이지

생활코딩 React 강의

16.1 이벤트 state props 그리고 render 함수

16.2 이벤트 설치

16.3 이벤트에서 state 변경하기

16.4 이벤트 bind 함수 이해하기

16.5 이벤트 setState 함수 이해하기

https://youtu.be/kviidk347nU

 

React - 16.1. 이벤트 state props 그리고 render 함수

React를 처음 시작하는 분들에게 권하는 강의입니다. 이 수업은 아래와 같은 웹애플리케이션을 React를 이용해서 완성하는 것이 큰 목표입니다. https://egoing.github.io/react-tutorial-example/ 소스코드

youtu.be

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Function/bind

 

Function.prototype.bind() - JavaScript | MDN

bind() 메소드가 호출되면 새로운 함수를 생성합니다. 받게되는 첫 인자의 value로는 this 키워드를 설정하고, 이어지는 인자들은 바인드된 함수의 인수에 제공됩니다.

developer.mozilla.org