반응형
섹션 3. State
1. State 소개
- state는 props의 값에 따라 내부의 구현에 필요한 데이터
- props는 사용자가 component를 사용하는 입장에서 중요한 것
2. State 사용
class App extends Component {
constructor(props) {
super(props);
this.state = {
Subject: { title: "WEB", sub: "World wid Web!" }
};
}
render() {
return (
<div ClassName="App">
<Subject>
title={this.state.Subject.title}
sub={this.state.Subject.sub}
</Subject>
<TOC></TOC>
<Content></Content>
</div>
);
}
}
export default App;
- App.js가 내부적으로 사용된다면 state를 통해 사용
- Component를 실행할 때 constructor 함수는 가장 먼저 실행되며 초기화를 담당
- state 값을 subject 컴포넌트에 props 값으로 전달하고 싶을 때, 상위 컴포넌트의 state 값을 하위 컴포넌트의 props의 값으로 전달 가능
3. key
class App extends Component {
constructor(props) {
super(props);
this.state = {
Subject: { title: "WEB", sub: "World wid Web!" },
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() {
return (
<div ClassName="App">
<Subject>
title={this.state.Subject.title}
sub={this.state.Subject.sub}
</Subject>
<TOC data={this.state.contents}></TOC>
<Content></Content>
</div>
);
}
}
import React, { Component } from "react";
class TOC extends Component {
render() {
var lists = [];
var data = this.props.data;
var i = 0;
while (i < data.length) {
lists.push(<li key={data[i].id}><a href={"/contenst/" + data[i].id}>{data[i].title}</a></li>);
i = i + 1;
}
return (
<nav>
<ul>
{lists}
</ul>
</nav>
);
}
}
export default TOC;
- TOC.js를 통하지 않고 내부 데이터의 목록을 바꾸기 가능
- lists.push(<li><a href={"/contenst/" + data[i].id}>{data[i].title}</a></li>); 처럼 여러 개의 element를 자동으로 생성하는 경우에는 key라고 하는 props를 가져야 한다는 에러 메세지가 발생
- App 컴포넌트의 내부 state를 TOC에 주입하는 것을 통하여 TOC의 내부 데이터를 바뀌게 할 것
섹션 4. 이벤트
1. 이벤트 state props 그리고 render 함수
- props, state, event가 서로 상호작용하면서 어플리케이션의 역동성을 부여
- react에서는 props나 state의 값이 바뀌면 해당되는 컴포넌트의 render()함수가 호출되도록 약속되어있음
- render 함수는 어떤 html을 표시할 것인가를 결정
- props나 state의 값이 바뀌면 해당 컴포넌트의 render 함수 재호출
- html(화면)이 다시 그려짐
import React, { Component } from "react";
import TOC from "./components/TOC";
import Content from "./components/Content";
import Subject from "./components/Subject";
import "./App.css";
class App extends Component {
constructor(props) {
super(props);
this.state = {
mode: "welcome",
Subject: { title: "WEB", sub: "World wid Web!" },
welcome: { title: "Welcom", 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() {
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>
);
}
}
export default App;
- mode 값에 따라서 다른 render()함수가 호출되게 함 (아직 직접 mode를 바꿔줘야함)
2. 이벤트 설치
- Subject 컴포넌트 내용을 가지고 와서 App에 도입 후 이벤트를 구현
import React, { Component } from "react";
import TOC from "./components/TOC";
import Content from "./components/Content";
import Subject from "./components/Subject";
import "./App.css";
class App extends Component {
constructor(props) {
super(props);
this.state = {
mode: "welcome",
Subject: { title: "WEB", sub: "World wid Web!" },
welcome: { title: "Welcom", 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() {
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> */}
<header>
<h1>
<a
href="/"
onClick={function (e) {
e.preventDefault(); // 이벤트의 기본 동작 금지
}}>{this.state.Subject.title}</a></h1>
{this.state.Subject.sub}
</header>
<TOC data={this.state.contents}></TOC>
<Content title={_title} desc={_desc}></Content>
</div>
);
}
}
export default App;
- 아직 Web을 클릭 했을 때 mode가 welcome으로 바뀌지 않음
3. 이벤트에서 state 변경하기
<header>
<h1><a href="/" onClick={fuction(e) {
e.preventDefault(); // 이벤트의 기본 동작 금지
// this.state.mode = 'welcome'; -> this 값이 아무것도 셋팅 X
this.setState({
mode:'welcome'
})
}.bind(this)}>{this.state.subject.title}</a></h1>
{this.state.subject.sub}
</header>
- 이벤트 함수 내의 this의 값은 아무것도 셋팅되어 있지 않음 -> bind(this) 코드를 추가해주어야 함
- 이벤트 함수 내에서 state 값 변경 (this.setState({변경값})) 전달
- Web 클릭 -> mode 값이 welcome으로 바뀜
4. 이벤트 bind 함수 이해하기
- render 함수 내에서 this는 컴포넌트 자신을 가리키는데, 함수 안에서 this는 아무것도 가리키지 않
- this값을 확실히 하기 위해서 bind함수를 사용
- bind() → 기존 함수를 복제하여 this 값을 지정 후 새로 만든다.
5. 이벤트 setState 함수 이해하기
- 컴포넌트 생성할 때 state 값은 직접 변경 가능
- 컴포넌트의 생성이 끝난 후에 동적으로 state의 값을 바꿀 때에는 this.state.mode = ‘welcome’;처럼 변경 불가
- setState()함수를 통해 변경하고 싶은 객체를 전달하는 방식으로 변경해야 함
6. 컴포넌트 이벤트 만들기 1, 2, 3
import React, {Component} from 'React';
import TOC from "./components/TOC";
import Subject from "./components/Subject";
import Content from "./components/Content";
import './App.css';
class App extends Component {
constructor(props) {
super(props);
this.state = {
mode:'welcome',
selected_contented_id:2,
subject:{title:'WEB', sub:'World Wid Web!'},
welcome:{title:'Welcome', desc:'Hi, 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() {
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 = this.state.contents[i].title;
_desc = this.state.contents[i].desc;
break;
}
i = i + 1;
}
}
return (
<div className="App">
<Subject
title={this.state.subject.title}
sub={this.state.subject.sub}>
onChangePage={fuction(){
this.setState({mode:'welcome'});
}.bind(this)}
</Subject>
<TOC
onChangePage={function(id){
this.setState({
mode:'read',
selected_content_id:Number(id)
});
}.bind(this)}
data={this.state.contents}
></TOC>
<Content title={_title} desc={_desc}></Content>
</div>
);
}
}
export default App;
import React, {Component} from 'React';
class Subject extends Component {
render() {
return (
<header>
<h1><a href="/" onClick={function(e){
e.preventDefault();
this.props.onChangePage();
}.bind(this)}>{this.props.title}</a></h1>
{this.props.sub}
</header>
);
}
}
export default Subject;
import React, {Component} from 'React';
class TOC extends Component {
render() {
var lists = [];
var data = this.props.data;
var i = 0;
while (i < data.length) {
lists.push(
<li key={data[i}.id>
<a
href={"/content/"+data[i].id}
data-id={data[i].id} // data-""
onClick={function(e){
e.preventDefault();
this.props.onChangePage(e.target.dataset.id); // dataset.""
}.bind(this)}
>{data[i].title}</a>
</li>);
i = i + 1;
}
return (
<nav>
<ul>
{lists}
</ul>
</nav>
);
}
}
export default TOC;
- Subject, TOC 컴포넌트에 onChangePage라는 이벤트를 만
- 해당 이벤트에 함수를 설치해주면 이벤트가 발생
- props로 전달된 onChagePage라는 함수를 호출
- e.target.dataset.id 를 통해 값을 꺼
섹션 5. Create 기능 구현
1. 베이스 캠프
- redux는 데이터를 각각의 컴포넌트들에 분산해서 보관하는 것이 아니라, 하나의 데이터 저장소가 있어서, 그와 관련된 모든 컴포넌트들이 알아서 바뀌게 함
2. create 구현 : 소개
- CRUD : Create, Read, Update, Delete
- Control.js 구현
import React, { Component } from "react";
class Control extends Component {
render() {
return (
<ul>
<li>
<a
href="/create"
onClick={function (e) {
e.preventDefault();
this.props.onChangeMode("create");
}.bind(this)}
>
create
</a>{" "}
</li>
<li>
<a
href="/update"
onClick={function (e) {
e.preventDefault();
this.props.onChangeMode("update");
}.bind(this)}
>
update
</a>
</li>
<li>
<input
onClick={function (e) {
e.preventDefault();
this.props.onChangeMode("delete");
}.bind(this)}
type="button"
value="delete"
></input>
</li>
</ul>
);
}
}
export default Control;
3. create 구현 : mode 변경 기능
- Control.js 추가 구현
// App.js
return (
<div className="App">
<Subject
title={this.state.subject.title}
sub={this.state.subject.sub}>
onChangePage={function(){
this.setState({mode:'welcome'});
}.bind(this)}
</Subject>
<TOC
onChangePage={function(id){
this.setState({
mode:'read',
selected_content_id:Number(id)
});
}.bind(this)}
data={this.state.contents}
></TOC>
<Control onChangeMode={function(_mode){
this.setState({
mode:_mode;
});
}.bind(this)}></Control>
<Content title={_title} desc={_desc}></Content>
</div>
);
// Control.js
import React, { Component } from 'react';
class Control extends Component {
render(){
return (
<ul>
<li><a href="/create" onClick={function(e){
e.preventDefault();
this.props.onChangeMode('create');
}.bind(this)}>create</a></li>
<li><a href="/update" onClick={function(e){
e.preventDefault();
this.props.onChangeMode('update');
}.bind(this)}>update</a></li>
<li><input onClick={function(e){
e.preventDefault();
this.props.onChangeMode('delete');
}.bind(this)} type="button" value="delete"></input></li>
</ul>
);
}
4. create 구현 : mode 전환 기능
- App컴포넌트의 mode가 create가 될때, ReadContent가 CreateContent로 바꾸기
// App.js
render() {
var _title, _desc, _article = null;
if (this.state.mode === 'welcome') {
_title = this.state.welcome.title;
_desc = this.state.welcome.desc;
_article = <ReadContent title={_title} desc={_desc}></ReadContent>;
} 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 = this.state.contents[i].title;
_desc = this.state.contents[i].desc;
_article = <ReadContent title={_title} desc={_desc}></ReadContent>;
break;
}
i = i + 1;
}
} else if (this.state.mode === 'create') {
_article = <CreateContent></CreateContent>
}
return (
<div className="App">
<Subject
title={this.state.subject.title}
sub={this.state.subject.sub}>
onChangePage={function(){
this.setState({mode:'welcome'});
}.bind(this)}
</Subject>
<TOC
onChangePage={function(id){
this.setState({
mode:'read',
selected_content_id:Number(id)
});
}.bind(this)}
data={this.state.contents}
></TOC>
<Control onChangeMode={function(_mode){
this.setState({
mode:_mode;
});
}.bind(this)}></Control>
<Content title={_title} desc={_desc}></Content>
</div>
);
// ReadContent.js
import React, {Component} from 'React';
class ReadContent extends Component {
render() {
return (
<article>
<h2>{this.props.title}</h2>
{this.props.desc}
</article>
);
}
}
export default ReadContent;
//CreateContent.js
import React, { Component } from "react";
class CreateContent extends Component {
render() {
return (
<article>
<h2>Create</h2>
<form>
</form>
</article>
);
}
}
export default CreateContent;
5. create 구현 : form
import React, {Component} from 'React';
class CreateContent extends Component {
render() {
return (
<article>
<h2>Create</h2>
<form action="/create_process" method="post"
onSubmit={function(e){
e.preventDefault();
}.bind(this)}
>
<p><input type="text" name="title"
placeholder="title"></input></p>
<p>
<textarea name="desc" placeholder="description"></textarea>
</p>
<p>
<input type="submit"></input>
</p>
</form>
</article>
);
}
}
export default CreateContent;
6. create 구현 : onSubmit 이벤트
// App.js
else if (this.state.mode === 'create') {
_article = <CreateContent onSubmit={function(_title, _desc){
}.bind(this)}></CreateContent>
}
import React, {Component} from 'React';
class CreateContent extends Component {
render() {
return (
<article>
<h2>Create</h2>
<form action="/create_process" method="post"
onSubmit={function(e){
e.preventDefault();
this.props.onSubmit(
e.target.title.value,
e.target.desc.value
);
}.bind(this)}
>
<p><input type="text" name="title"
placeholder="title"></input></p>
<p>
<textarea name="desc" placeholder="description"></textarea>
</p>
<p>
<input type="submit"></input>
</p>
</form>
</article>
);
}
}
export default CreateContent;
7. create 구현 : contents 변경, shouldComponentUpdate
- 배열에 데이터를 추가하는 방법으로는 2가지가 있음
- push → 원래 배열이 바뀜
- concat → 원래 배열이 바뀌지 않음 - 새로운 배열 리턴
class App extends Component {
constructor(props) {
super(props);
this.max_content_id = 3;
...
render() {
...
} else if (this.state.mode === 'create') {
_article = <CreateContent onSubmit={function(_title, _desc){
this.max_content_id = this.max_content_id + 1;
var _contents = this.state.contents.concat(
{id:this.max_content_id, title:_title, desc:_desc}
)
this.setState({
content:_contents
});
}.bind(this)}></CreateContent>
}
return (
<div className="App">
<Subject
title={this.state.subject.title}
sub={this.state.subject.sub}>
onChangePage={fuction(){
this.setState({mode:'welcome'});
}.bind(this)}
</Subject>
<TOC
onChangePage={function(id){
this.setState({
mode:'read',
selected_content_id:Number(id)
});
}.bind(this)}
data={this.state.contents}
></TOC>
<Control onChangeMode={function(_mode){
this.setState({
mode:_mode;
});
}.bind(this)}></Control>
{_article}
</div>
);
}
}
export default App;
섹션 6_Update & Delete 기능 구현
1. update 구현
//UpdateContent.js
import React, { Component } from "react";
class UpdateContent extends Component {
render() {
return (
<article>
<h2>Update</h2>
<form
action="/create_process" method="post" onSubmit={function (e) {
e.preventDefault();
}.bind(this)}
>
<p>
<input type="text" name="title" placeholder="title"></input>
</p>
<p>
<textarea name="desc" placeholder="description"></textarea>
</p>
<p>
<input type="submit"></input>
</p>
</form>
</article>
);
}
}
export default UpdateContent;
2. update 구현 : form
- inputFormalHandler 함수를 만들어서 코드를 간결하게 표현
//UpdateContent.js
import React, { Component } from "react";
class UpdateContent extends Component {
constructor(props){
super(props);
this.state = {
title:this.props.data.title,
desc:this.props.date.desc
}
this.inputFormHandler = this.inputFormHandler.bind(this);
}
inputFormHandler(e){
this.setState({[e.target.name]:e.target.value});
}
render() {
return (
<article>
<h2>Update</h2>
<form
action="/create_process" method="post" onSubmit={function (e) {
e.preventDefault();
}.bind(this)}
>
<p>
<input
type="text"
name="title"
placeholder="title"
value={this.state.title}
></input>
</p>
<p>
<textarea onChange={this.inputFormHandler}
name="desc"
placeholder="description"></textarea>
</p>
<p>
<input type="submit"></input>
</p>
</form>
</article>
);
}
}
export default UpdateContent;
3. update 구현 : state 변경
import React, {Component} from 'React';
class UpdateContent extends Component {
constructor(props){
super(props);
this.state = {
title:this.props.data.title,
desc:this.props.date.desc
}
this.inputFormHandler = this.inputFormHandler.bind(this);
}
inputFormHandler(e){
this.setState({[e.target.name]:e.target.value});
}
render() {
return (
<article>
<h2>Update</h2>
<form action="/create_process" method="post"
onSubmit={function(e){
e.preventDefault();
this.props.onSubmit(
this.state.id,
this.state.title,
this.state.desc
);
}.bind(this)}
>
<input type="hidden" name="id" value={this.state.id}></input>
<p>
<input
type="text"
name="title"
placeholder="title"
value={this.state.title}
onChange={this.inputFormHandler}
></input>
</p>
<p>
<textarea onChange={this.inputFormHandler}
name="desc"
placeholder="description"
value={this.state.desc}></textarea>
</p>
<p>
<input type="submit"></input>
</p>
</form>
</article>
);
}
}
export default UpdateContent;
4. delete 구현
- window.confirm → 사용자에게 진짜 삭제할 건지 확인
// App.js
class App extends Component {
...
<Control onChangeMode={function(_mode){
if(_mode === 'delete'){
if(window.comfirm('really?')){
var _contents = Array.from(this.state.contents);
var i = 0;
while(i < this.state.contents.length){
if(_contents[i].id === this.state.selected_content_id){
_contents.splice(i,1)
break;
}
i = i + 1;
}
this.setState({
mode:'welcome',
contents:_contents
});
alert('deleted!');
}
} else {
this.setState({
mode:_mode;
});
}
}.bind(this)}></Control>
{this.getContent()}
);
}
}
export default App;
// Control.js
import React, { Component } from 'react';
class Control extends Component {
render(){
return (
<ul>
<li><a href="/create" onClick={function(e){
e.preventDefault();
this.props.onChangeMode('create');
}.bind(this)}>create</a></li>
<li><a href="/update" onClick={function(e){
e.preventDefault();
this.props.onChangeMode('update');
}.bind(this)}>update</a></li>
<li><input onClick={function(e){
e.preventDefault();
this.props.onChangeMode('delete');
}.bind(this)} type="button" value="delete"></input></li>
</ul>
);
}
반응형
'WINK-(Web & App) > HTML & CSS & JS 스터디' 카테고리의 다른 글
[2024 신입부원 기초 스터디] 이종윤 #3주차 (JS 첫번째 수업) (0) | 2024.05.10 |
---|---|
[2023 신입부원 기초 스터디] 박승환 #8주차 마지막 JS (0) | 2023.07.03 |
[2023 신입부원 심화 스터디] 신진욱 #마지막주 React.js 섹션 3 - 6 #귀칼보단 리액트지 ㅋ (0) | 2023.07.02 |
[2023 신입부원 심화 스터디] 김윤희 #마지막주차 React.js 섹션3 ~ 7 #치타는힘드러 (0) | 2023.07.01 |
[2023 신입부원 기초 스터디] 이총명 #8주차 - JS 해치웠나..? (0) | 2023.07.01 |