자식컴포넌트에서 발생한 이벤트를 부모컴포넌트에서 핸들링하고싶을때가 있다.

 

1.부모컴포넌트에 핸들링함수를 만든다.

2.자식컴포넌트에 props로 넘겨준다.

3.자식컴포넌트에서 이벤트 발생시 해당 props 함수를 호출한다. 필요한 값은 인자로 넘기면 된다.

컴포넌트끼리 핸들링함수의 인자를 통해 연결된다.

<App.js>

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
import React, { Component } from "react";
import logo from "./logo.svg";
import "./App.css"//일케해놓으면 App 컴포넌트가 로드될때 같이 import돼서 쓸수있게된다. 즉 <App/> 얘가 쓰일때
//css가 따라오게끔. 동적로드하는 효과.
import Subject from "./components/Subject";
import Content from "./components/Content";
import Article from "./components/Article";
import Controls from "./components/Controls";
import CreateForm from "./components/CreateForm"
import UpdateForm from "./components/UpdateForm"
class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      subject: { title: "WEB", desc: "world wide web!" },
      mode: "welcome",
      selected0,
      contents: [
        { id: 0, title: "HTML", desc: "HyperText Management Language" },
        { id: 1, title: "CSS", desc: "씨에스에스" },
        { id: 2, title: "javascript", desc: "자바스크립트" }
      ]
    
    };
  }
 
  getContent() {
 
    var _mode=this.state.mode;
    if (_mode === "read") {
      var article = this.state.contents[this.state.selected];
      return <Article article={article}></Article>;
    } else if (_mode === "welcome") {
      return <Article article={this.state.subject}></Article>;
    } else if(_mode==="create"){
      return <CreateForm addContent={this.addContent.bind(this)}></CreateForm>;
    } else if(_mode==="update"){
      return <UpdateForm data={this.state.contents[this.state.selected]} updateContent={this.updateContent.bind(this)}></UpdateForm>;
    }
  }
  addContent(title,desc){
    var len=this.state.contents.length;
    var newContents=Array.from(this.state.contents);
    newContents.push({id:len,title:title,desc:desc});
    this.setState({
      contents:newContents,
      mode:'read',
      selected:len
    })
  }
  updateContent(id,title,desc){
    var newContents=this.state.contents;
    newContents[id].title=title;
    newContents[id].desc=desc;
    this.setState({
      contents:newContents,
      mode:'read',
      selected:id
    });
  }
  changeMode(mode){
    this.setState({
      mode:mode
    });
  }
 
  changeArticle(i) {
    this.setState({
      mode:'read',
      selected: i
    });
  }
  render() {
    return (
      <div>
        <Subject
          title={this.state.subject.title}
          sub={this.state.subject.sub}
          onClicked={this.changeMode.bind(this)}
        ></Subject>
        <Content
          contents={this.state.contents}
          onClicked={this.changeArticle.bind(this)}
        ></Content>
        <Controls
          controls={this.state.controls} onClicked={this.changeMode.bind(this)}
        ></Controls>
        {this.getContent()}
      </div>
    );
  }
}
export default App;
 
cs

Content 컴포넌트를 사용할때, chageArticle 메서드를 넘겨준다.

이 때 bind를 해주는 이유는

자바스크립트에서 this키워드는 해당 객체를 나타내는게 아니라 어디서 호출되는가를 나타낸다.
changeArticle 메서드는 전역객체에서 호출되기 때문에 함수 내 코드에 this.setState의 this는 전역객체를 가리키게 된다.

당연히 전역객체에 state가 없기 때문에 오류가 난다.

이 메서드를 누가 호출 하는것 인가를 지정해줘야 한다.

bind(this)를 해주면 이 메서드는 호출될때 App컴포넌트 객체에서 호출된다는 뜻이 되어서

this.setState를 할 때 애가 App컴포넌트객체라고 생각하고 작동한다.

 

this랑 bind에 대한 개념은 이 형님이 잘 정리해 놓으셨다.

https://blueshw.github.io/2018/03/12/this/

 

https://blueshw.github.io/2018/03/12/this/

 

blueshw.github.io

 

<Content.js>

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
import React, { Component } from "react";
import { tsConstructorType } from "@babel/types";
class Content extends Component {
  constructor(props) {
    super(props);
    
  }
  changePage(e){
    e.preventDefault();
    this.props.onClicked(e.target.dataset.id);
    
  }
  render() {
    var list = [];
    var data=this.props.contents;
    var i=0;
    while(i<data.length){
      var li=<li><a href='#' data-id={data[i].id} onClick={this.changePage.bind(this)}>{data[i].title}</a></li>
      list.push(li);
      ++i;
    }
    return (
      <nav>
        <ul>{list}</ul>
      </nav>
    );
  }
}
 
export default Content;
 
cs

자식 컴포넌트에서는 a태그를 쫙 깔아주는데

onClick=핸들링함수 일케 해주면 이벤트가 알아서 해당 함수의 인자로 전달된다.

changePage함수가 실행되고 이 때도 마찬가지로 바인딩을 해줘야 changePage 내부의 this키워드를 제대로 사용할 수 있다.

 

e.preventDefault()로 a태그가 기본적으로 수행하는 이벤트처리를 막아주고

this.props.onClicked()를 호출한다. 즉 App컴포넌트에서 넘어온 핸들링 함수를 수행한다.

html5부터 추가됐다던가 뭐던가 하튼간 태그에 data-로 시작하는 속성을 달아주면

dataset안에 속성명으로 속성들이 생긴다.

data-id={} 이런식으로 id값들을 세팅해줬기 때문에 이제 a태그의 dataset속성 안에 id값들이 배정된다.

e.target으로 이벤트가 발생된 a태그를 찾아내고 dataset에 id를 찾아내서

App컴포넌트에서 props로 넘어온 함수에 인자로 넘긴다.

 

그럼 App컴포넌트에선 클릭된 놈의 내용을 맨 밑에 띄워준다.

onClicked말고도 값이 변경될때마다 냄새를 맡는 onChange도 있고

form에서는 onSubmit 쓰면된다.

 

<UpdateForm.js>

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import React, { Component } from "react";
class UpdateForm extends Component {
  constructor(props) {
    super(props);
    this.state = {
      id: props.data.id,
      title: props.data.title,
      desc: props.data.desc
      
    };
    this.changeHandler=this.changeHandler.bind(this);
  }
  changeHandler(e){
      this.setState({[e.target.name]:e.target.value});
      //javascript 신종문법!
      //if e.target.name==='title'이면 title:바꿔야하고 이런거 대신에 []로 처리해주면땡
  }
  render() {
    return (
      <div>
        <form
          action="#"
          method="post"
          onSubmit={function(e) {
            e.preventDefault();
 
            var title = e.target.title.value;
            var desc = e.target.desc.value;
            this.props.updateContent(this.props.data.id, title, desc);
          }.bind(this)}
        >
          <input
            name="title"
            value={this.state.title}
            placeholder="title"
            onChange={this.changeHandler}
          ></input>
          <input
            name="desc"
            value={this.state.desc}
            placeholder="desc"
            onChange={this.changeHandler}
          ></input>
          <input type="submit"></input>
        </form>
      </div>
    );
  }
}
 
export default UpdateForm;
//그냥 input으로 놓으면 값이 변경이안된다
/* 따라서 자신의 state에 title,desc를 세팅해놓고 input에서 이벤트가 발생할때마다 (onChange=)
state의 title,desc가 바뀌게끔 해줘야한다. 그러면 자동으로 input의 value도 바뀐값을 참조하게되므로 input에 있는 값이 바뀐다.
이때 굳이 props로 넘어온걸 state에 할당해서 바꿔주는이유는, props는 R/O이기 때문이다.
*/
 
cs

내용을 업데이트 해주는 form이다.

' > 리액트' 카테고리의 다른 글

[리액트]형상관리  (0) 2019.08.31
[리액트]앱 빌드/배포  (0) 2019.08.31
[리액트]props state  (0) 2019.08.31
[리액트]컴포넌트  (0) 2019.08.31
[리액트]플젝 만들기  (0) 2019.08.31

+ Recent posts