자식컴포넌트에서 발생한 이벤트를 부모컴포넌트에서 핸들링하고싶을때가 있다.
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",
selected: 0,
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/
<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 |