본문 바로가기

[자기계발]/유튜브로 코딩배우기

[생활코딩]React 강의-3 17강 Component 이벤트 만들기

반응형

17.1강 컴포넌트 이벤트 만들기

이벤트의 생산자가 되어보자,

 

         <header>
          <h1><a href="/" onClick={function(e){
            console.log(e);
            e.preventDefault();
            this.setState({
              mode: 'welcome'
            });
          }.bind(this)}>{this.state.subject.title}</a></h1>
          {this.state.subject.sub}
        </header>

a태그를 클릭했 을 때, onClick이라는 이벤트에 설채 해놓은 사용자정의 함수가

호출 되면서 우리는 app컴퍼넌트의 mode의 값을 welcome으로 바꾸는 코드

 

그런데 이 header의 코드는 원래 subject.js 안에 있던 코드이다.

그런데 수업을 단순하게 하기 위해서 이 파일을 주석처리하고 내용을

저렇게 header안에 옮겨놨다. 이해하기가 쉬워서

 

이제 이 바깥 쪽에 있는 코드를 주석화하고 본 코드를 살려보자.

 

우리는 subject라고 하는 저 컴퍼넌트의 제작자 또는 생산자 입장에서 

저것을 사용하려고 하는 이용자들에게 이렇게 얘기한다.

만약 이 서브젝트라는 컴퍼넌트를 사용할 때, 사용자가 여기 있는 이 링크를 클릭했을

때 어떠한 일이 일어나게 하고 싶다면, 즉, 이벤트를 설치하고 싶다면

 

 

 onChangePage 라는 이벤트를 쓰세요.

이벤트의 함수를 설치해 놓으면 이 a태크가 클릭 되었을 때 우리가 설치한

그 함수를 실행해 드릴게요.

 

우리가 만들려고 하는 서브젝트라고 하는 이 컴퍼넌트는 onChangePage라는

이벤트가 있어서 이 컴퍼넌트 안에서 링크를 클릭 했을 때, 이 이벤트의

설치한 함수를 호출하도록 만들려고 하는 것

 

사용자들은 어떻게 할까?

우리가 만든 이 Subject 컴퍼넌트는 페이지가 바뀌었을 때 여기를 누군가 클릭했을 때

사용자가 설치한 이 컴퍼넌트의 사용자가 설치한 이 함수를 호출해 주기만 하면 된다.

        <Subject 
          title={this.state.subject.title}
          sub={this.state.subject.sub}
          onChangePage={function(){
            alert('hihihi');
          }.bind(this)}
        >

 

어떻게 할까?

 

onChangePage라고 하는 이 함수는 어떤 형태로 Subject에 전달 될까?

'props' 이다

 

 

여기에 a태그를 onClikc했을 때, 함수가 실행이 이렇게 된다.

onClick={function(){}.bind(this)

그리고 실행 됐을 때 첫 번째 인자로 이벤트 객체(e)가 전달되는데 그 객체의

e.preventDefault(); 라고 하는 것을 호출해서 링크를 클릭했을 때 페이지가 

바뀌는 것을 막는 것.

그 다음, 이 Subject 컴퍼넌트의 onChangePage로 함수가 전달 된다.

        <header>
          <h1><a href="/" onClick={
            function(e){
            e.preventDefault();
            this.props.onChangePage()  
            }.bind(this)
          }
          >
          {this.props.title}</a></h1>
          {this.props.sub}
        </header>

그 함수를 여기에서 호출해주면 된다. 

this.props.onChangePage 

=>app.js의

function(){
            alert('hihihi');
          }.bind(this)

 

정리

우리는 Subject라고 하는 컴퍼넌트의 onChangePage 이벤트를 만들었다.

        <Subject 
          title={this.state.subject.title}
          sub={this.state.subject.sub}
          onChangePage={function(){
            alert('hihihi');
          }.bind(this)}
        >

그리고 저 이벤트에다가 이렇게 함수를 설치해 주면

          onChangePage={function(){
            alert('hihihi');
          }.bind(this)}

그 이벤트가 발생되었을 때 Subject.js에 있는 

          <h1><a href="/" onClick={
            function(e){
            e.preventDefault();
            this.props.onChangePage()  
            }.bind(this)
          }
          >

링크(WEB)를 클릭했을 때, 우리는 props로 전달된 onChangePage라는 함수를

호출하면 된다. 그렇게 해서 경고창hihihi가 뜬 것이다. 

 

만약에 hihi를 

          onChangePage={function(){
            this.setState({mode:'welcome'});
          }.bind(this)}

이렇게 바꾸어주면 

WEB을 눌렀을 때 State의 mode를 welcome으로 바꾸는 작업을 한다.

App이라고하는 컴퍼넌트의 mode의 갑싱 "read" -> "welcome"으로 바뀌고

화면이 잘 변경되었다. 우리는 이벤트 소비자에서 벗어나서 생산자가 되었다.

 

Q.

왜 밑에선 state 말고 props로 이벤트를 부르는걸까요..? 

A.

App.js에서 하위컴포넌트인 Subject 클래스를 사용할때 Subject의 props를 onChangePage로 입력을 하였어요~

추가적으로 부모클래스에서 자식클래스에게 값을 전달하기 위해 state를 사용하고, 그 state를 props를 통해 전달을 합니다.

 

 17.2강 컴포넌트 이벤트 만들기

 

Subect라고 하는 내가 만든 컴퍼넌트에 onChangePage라고 하는 이벤트를

우리가 만들어서 사용자에게 제공하였다.

 

이번에는 글 목록을 클릭했을 때 App이라고 하는 컴퍼넌트에 state의 mode를

read로 바꿀 것이다. 즉, 우리가 클릭한 것에 해당되는 컨텐트가 본문에 나오게 해볼 것이다.

 

App.js의 TOC라고 하는 컴퍼넌트에 똑같은 이름의 이벤트를 만들어보자

        <TOC
        onChangePage={function(){
          alert('hi');
        }.bind(this)}
        data={this.state.contents}>
        </TOC>

이러기 위해선 onChangePage라고 하는 props를 TOC.js 안에서 받아야한다.

        <a 
        href={"/content/"+data[i].id}
        onClick={function(e){
          e.preventDefault();
          this.props.onChangePage();
        }.bind(this)}
        >{data[i].title}</a>
        </li>);

onClick을 했을 때 function이 실행이 되고, 클릭했을 때 페이지가 다른페이지로 eload가 

안 되기 하기 위해서는, 이벤트 객체(e)를 받아서 객체에 

e.preventDefault 라는 함수를 실행하면 된다.

여기서 this의 props.에 onChangPage 라고 하는 저 props를 실행하면

App.js의 TOC의 함수가 실행이 되면서 경고창이 뜬다.

자 이제,

APP 컴퍼넌트의 State 중 mode 값을 read로 바꿔주면 된다.

        <TOC
        onChangePage={function(){
        this.setState({mode:'read'});
        }.bind(this)}
        data={this.state.contents}>
        </TOC>

17.3강 컴포넌트 이벤트 만들기

 

글 몰록에서 선택한 컨텐트 (HTML, CSS, JS)가

밑의 본문 HTML 쪽에 표시되게 해보려고 한다.

 

App의 state에다가 selected-content-id

이름을 줘서 윌가 현재 활성화된 선택된 컨텐트를 여기에다가 표시할 것이다.

그러면 그 값을 바탕으로 해서 이 컨텐트라고 하는 저 객체이 있는 id 값 중에

그 값과 일치하는 selected 컨텐트 id값과 일치하는 것을 본문에 표시하게 할 것이다.

class App extends Component {
  constructor(props){
    super(props);
    this.state = {
      mode:'read',
      selected_content_id:2,
      subject:{title:'WEB', sub:'World Wid 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'}
      ]
    }
  }

이 컨텐트를 바탕으로 3개의 글 몰록 중 누가 본문에 나올 것인가를 지정을 하는데[

어디서 하면 되냐면

밑에 있는 render에 mode가 read 일 때, 이 부분에서 하면 된다.

  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'){
      var i = 0;
      while(i < this.state.contents.length){
        var data = this.state.contents[i];
        if(data.id === this.state.selected_content_id) {
          _title = data.title;
          _desc = data.desc;
        break
        }
        i= i + 1;
      }
    }

현재 순번에 해당되는 컨텐트를 var = data 라고 하고

만약에 data의 id 값이 this.state의 selected컨텐트 id값이 일치하는 것이 발견된다면

title이 description 될 자격이 있다.

강제로 i문을 내버리는 코드인 break를 쓰면 break가 실행되는 순간에 조건문이 

끝나고, 조건문 바깥 쪽에 있는 코드들이 실행되기 시작한다.

 

페이지가 selected_content_id 값에 따라 바뀌는 것을 확인 했으면

이제는 뭘 해야하나?

 

TOC가 저기 있는 리스트니까, 저 리스트에 onChangepage 이벤트가 발생했을 때

우리는 this.setState를 통해서 모두의 값과 함께 selected_content_id 에 값을

0이라고 되어있는 부분의 값으로 해주면 된다.

        <TOC
        onChangePage={function(){
        this.setState({mode:'read',
        selected_content_id:0
        });
        }.bind(this)}
        data={this.state.contents}>
        </TOC>

 

App.js의 TOC onChangepage 이벤트를 실행시키는 부분은

TOC.js에서 onClick을 했을 때 바로 이 props를 실행 시키는 것을 통해서 이 함수를

실행해주는 것이다. TOC가 App.js에 이쓴 함수를 실행시키는 것. 

즉, 그것을 실행할 떄 인자로 우리가 클릭한 항목의 id값을 주면 된다.

이것을 하는 방법 2가지

 

data-id={data[i].id} 이런 속성을 주는 것이다.

이벤트 객체는 target 이라는 속성이 있다. 이 target이라는 속성은 그 이벤트가 발생한

태그 즉 a태그를 가리킨다. 그래서 우리가 그 이벤트 함수 내에서 e.target 이라고 하면

저 이벤트가 소재하고 있는 태그인 a태그를 가리킨다. 우리는 요걸 통해서

a태그를 알아냈으면, 그 a 태그를 갖고 있는 data-id 값에 접촉할 수 있게 된 것. 

 

TOC

<a

href={"/content/"+data[i].id}

data-id={data[i].id}

onClick={function(e){

e.target

debugger;

e.preventDefault();

this.props.onChangePage();

}.bind(this)}

>

id 가 2인데 이 값이 data[i].id 여기에 들어있는 값이다.

알아낸 정보를 onChangePage 함수를 호출하는 코드에 인자로 넣어  준다.

App의 onChangePage에서 id라는 매개변수를 주고 실행하면

State에서 selected_content_id값이 변하는 것을 볼 수 있다. 

숫자는 바뀌는데 안되는 이유는 그 값은 문자열이고

content의 id는 숫자이다. 데이터 형식이 다르다.

문자를 숫자로 바꿔주는 자바 스크립트의 명령중 하나인 Number로 감싸준다.

웹을 클릭하면 mode가 welcome이 되고  리스트 컨텐트를 클릭하면 read가 되어서

그것에 해당되는 selected_content_id 가 바뀌기 때문에 내용도 같이 잘 바뀐다.

 

App

        <TOC
        onChangePage={function(id){
        this.setState({mode:'read',
        selected_content_id:Number(id)
        });
        }.bind(this)}
        data={this.state.contents}>
        </TOC>

TOC

        (<li key={data[i].id}>
        <a 
        href={"/content/"+data[i].id}
        data-id={data[i].id}
        onClick={function(e){
          e.preventDefault();
          this.props.onChangePage(e.target.dataset.id);
        }.bind(this)}
        >{data[i].title}</a>
        </li>);

정리

속성을 이용하는 방법

onClick이라고 하는 저 속성은 저 이벤트를 실행시킬 때 우리가

e의 target의 dataset의 id를 통해서 추출 했는데 

 

data값의 이름에 따라서 밑의 id도 달라진다.

 

data-id={data[i].id}

<a

onClick={function(e){

e.preventDefault();

this.props.onChangePage(e.target.dataset.id);

}.bind(this)}

>

 

속성을 이용하지 않고 하는 방법

bind의 두 번 째 인자로 data[i].id 라는 값을 주면 이 bind는 두 번째 인자로 들어온

이 값을 이 함수의 첫 번쨰 매개 변수의 값으로 넣어준다. 그리고 기존에 있었던 것은

뒤로 한 칸씩 밀리는 것. 이런식으로 처리해도 똑같이 적용된다.

 

function(id, e){

e.preventDefault();

this.props.onChangePage(id);

}.bind(this, data[i], id)}

 

#이번 강의를 이해하기 위해 가장 중요한 부분은 첫 1분동안 나오는 내용인 것 같습니다. 왜 'selected-content-id'란 값을 state에 추가했는지, 이 코드의 역할이 무엇인지를 분명히 강사님은 첫 부분에 말씀해 주셨지만 강의가 끝나고 나면 기억에 남지 않습니다. 후반부에 나오는 target의 기능, data-id의 역할 등을 쫓아가다보면 앞의 내용이 없어져버리거든요. 후에 복습을 하려하면 target의 기능, data-id의 역할은 이해하겠는데 왜 이게 필요한지를 모르기 때문에 붕 뜬 기분이 들고 막막해집니다. 즉, 이 코드를 통해서 만들고자 하는 기능을 명확히하고 그 시발점을 어디서부터 가르는지를 정확히 인지하고 계신다면 target의 기능이나 data-id의 역할은 부수적인거라고 생각합니다.

 

 

#// 1. data-id: // evenet 객체는 target이라는 속성이 있고, // target은 이벤트가 발생한 태그 a태그를 가리킵니다. // event 함수 내에서 e.target은 <a>태그를 가리킨다. // 그러하면, <a>태그의 속성에 접근 할 수 있다. // data- 접두사로 시작되는 속성은 dataset이라는 속성으로 접근 할 수 있다. // e.target.dataset.id 로 data-id를 찾을 수 있다. // 2. bind(this, id) // bind(this, 두번째 인자)를 주게 되면, // function(e) → function(id, e)가 되면서, 파라미터가 하나씩 밀리게 된다.

 

Q.

TOC.js 에서, data-id = {data[i].id}가 아니라 data_id로 했는데 작동 안되는데 이유가 무엇인가요? 변수명에 -를 사용하면 뭔가 규칙이 있는거 같은데 설명해주실분 ㅠㅠ

 

A.

다른 개념이에요 저도 정확히 알고 있는건 아니고... 그냥 대략적으로 이해하고 설명 드리는거니 제 댓글 읽으시고 나중에 꼭 타 강의영상, 강의 글 참고 부탁드립니다.

html의 태그들 (<a> <input> 등등등) 에는 여러가지 attribute 즉 속성을 넣을 수 있습니다. 강의에 나오는 a태그로 예를 들면 꺽쇠 안에 들어가는 href, onClick 가 그것입니다. (임의로 원하는 속성을 만들 수 도있습니다! 'test', 'babo' 저희 맘대루요.) 그중에는 data라는 속성이 있습니다. 이 속성은 페이지를 해석 할 때 dataset 이라는 걸로 해석하는데요 일종의 data보따리처럼 다루는 것 같습니다.

선생님이 하신 건 data라는 큰 보따리에 id라는 작은 보따리를 만들어서 값을 넣는 과정이라고 보시면 되겠습니다. 그러한 과정을 하기위한 규칙은 data 뒤에 _(언더바) 가 아닌 -(하이픈, 대시)를 붙이고 작은 보따리 이름을 붙이는 것입니다. ex) data-id, data-test, data-babo

작성자님께서 하신 건 dataset을 이용하는 것이 아닌 data_id라는 임의의 속성을 만드신 겁니다. 그래서 e.target.dataset.id (a태그의 dataset의 id)를 찾느 코드는 안먹히는 거구요. 만약 data_id로 작동을 원하신다면 단순하게 e.target.data_id라고 하면 '아마' 작동 할 겁니다.

반응형