CRUD - Create, Read, Update, Delete로 웹페이지의 기본적인 데이터 처리기능을 묶어서 일컫는 말이다.
앞서 작성했던 포스트는 title과 sub가 존재하는 Subject Component가 있고
HTML,CSS,JS에대해서 Contents에 접근할 수 있게하는 nav같은 TOC Component
각각의 TOC요소를 클릭하면 반응하여 Contents의 내용이 변경되며 표시되는 Conetnt Component가 존재했었다.
여기서 create, update, delete 기능을 가지는 Control Component를 추가한 모습이다.
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>
);
}
}
앞서 사용했던 onClick에 function을 넣어 클릭됬을때 onChangMode가 실행되면서 그에 맞는 mode로 바뀌는 함수이다.
상위 Component에 실제로 Control Component가 사용되는 모습인데 이곳에 OnChangeMode가 정의되어있다.
<Control onChangeMode={function(_mode){
this.setState({
mode:_mode
});
}.bind(this)}
onClick이벤트에 의해 this.props.onChageMode('mode값')에서 받아오는 변수가 setState에 의해 mode값이 변경된다.
여기서 가장쉬운 delete기능먼저 보겠다.
<Control onChangeMode={function(_mode){
if(_mode === 'delete'){
if(window.confirm('really?')){
var _contents = Array.from(this.state.contents);
var i = 0;
while(i < _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>
onChageMode로 변경된 mode값이 'delete'라면 먼저 window.confirm()으로 정말 삭제하겠냐는 창을 먼저 띄운다.
confirm()함수는 확인을 누르게되면 true값이 반환되고 취소를 누르게되면 false값이 반환되는 함수이기때문에 if(window.confirm('really?')) 가 true값이 반환되면 실행되는 내용은
var _contents = Array.from(this.state.contents);
먼저 _contents에 지금 this.state.contents를 객체를 복사해 새로운배열객체를 만드는 함수가 Array.from()이다.
while(i < _contents.length){
if(_contents[i].id === this.state.selected_content_id){
_contents.splice(i,1);
break;
}
i = i + 1;
}
이제 contents의 길이만큼 _contents[i].id와 this.state.selected_content_id값을 비교하면서 일치할때 삭제기능을 넣을건데 아까 복사해놓은 _contents라는 배열객체의 index요소를 삭제하는 함수가 _contents.splice(i,1)가된다.
그 일치하는 i값부터 몇개를 삭제하냐는 1이 들어가서 i값 하나만을 삭제하기를 원하기때문에 1을 넣어준 모습이다.
this.setState({
mode:'welcome',
contents:_contents
});
alert('deleted!');
만약 삭제를 완료했다면 mode를 다시 welcome으로 바꾸고 contents를 삭제가 완료된 객체배열인 _contents로 바꿔주는 모습이다.
삭제가 완료된 객체배열로 state값을 변경해줘야 변경해준 모습이 나타나기때문
완료가 됬다면 삭제가 완료됬다는 deleted를 띄어준다.
이로써 delete의 기능을 먼저 살펴봤다.
우선 create기능을 구현하기전에 content Component를 읽기전용으로 ReadContent라는 이름으로 Component를 변경하고 불필요한 부분은 없애준다.
class ReadContent extends Component{
render(){
return (
<article>
<h2>{this.props.title}</h2>
{this.props.desc}
</article>
);
}
}
그리고 CreateContent라는 이름의 Component를 생성하는데 이는
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>
);
}
}
이는 모드가 Create가되었을 때 Contenet가표시할 내용의 폼에 title과 desc에 채운뒤 submit버튼을 클릭했을 때 실행되는 함수인 onSubmit을 설정하는데 인자는 (e.target.title.value, e.target.desc.value)가 된다는 소리이다.
(e.target.title또는desc.value은 내가 form에 작성한 내용을 가르키는 것이다.)
onSubmit을 정의는 이부분인데
getContent(){
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 _content = this.getReadContent();
_article = <ReadContent title={_content.title} desc={_content.desc}></ReadContent>
}else if(this.state.mode === 'create'){
_article = <CreateContent onSubmit={function(_title, _desc){
this.Max_content_id = this.Max_content_id + 1;
var _contents = Array.from(this.state.contents);
_contents.push({id:this.Max_content_id, title:_title, desc:_desc});
this.setState({
contents:_contents,
mode:'read',
selected_content_id:this.Max_content_id
});
}.bind(this)}></CreateContent>
}
return _article;
}
이는 render()함수안에 너무 난잡한내용이 많아서 그내용을 _article이라는 변수에 담아서
{this.getContent()}
으로 원래 ContnetComponent가 있어야할 위치에 불러오게 만든 모습이다.
그리고 this.state.mode값이 'create'값이 됬을 때 _article에 CreateContent인 Component를 넣는 모습이다. 이안에 onSubmit의 내용을 정의하는데 먼저 가장상위 Component인 App에
this.Max_content_id = 3;
를 추가해주는데 이는 내가 가지고있는 Content의 Max크기만큼 값을 준다. (나는 content가 HTML,CSS,JS 3개이기때문에 3을 줬다)
이제 onSubmit의 정의를 살펴보면 function의 매개변수는 인자로받은 (e.target.title.value, e.target.desc.value)을 각각의 매개변수로(_title,_desc)로 받는다.
var _contents = Array.from(this.state.contents);
_contents.push({id:this.Max_content_id, title:_title, desc:_desc});
this.setState({
contents:_contents,
mode:'read',
selected_content_id:this.Max_content_id
});
그리고 다시 복사한 객체배열을 _contents에 담아 id값과 title, desc를 모두 push하는 모습이다.
그리고 마지막으로 setState로 contents에 새로운 id와 title, desc가 담긴 객체배열인 _contents으로 바꿔주는 모습이고 selected_content_id값또한 증가된 값으로 바꿔주는 모습이다.
마지막으로 mode값을 'read'로 바꾸어 추가된 모습을 'read' 모드로 확인하는 모습이다.
우선 getReadContent함수를 만들어서 앞으로 중복되는 부분이 있을 수 있으니 리팩터링을 해보자.
getReadContent(){
var i = 0;
while(i < this.state.contents.length){
var data = this.state.contents[i];
if(data.id === this.state.selected_content_id) {
return data;
}
i = i + 1;
}
}
따라서 mode값이 'read'일 때 코드는 이렇게 간단히 바뀔 수 있다.
else if(this.state.mode === 'read'){
var _content = this.getReadContent();
_article = <ReadContent title={_content.title} desc={_content.desc}></ReadContent>
그리고 이제 getContent()에 this.state.mode === 'update'라면 실행되는 부분을 추가한다
else if(this.state.mode === 'update'){
_content = this.getReadContent();
_article = <UpdateContent data={_content}
onSubmit={function(_id, _title, _desc){
var _contents = Array.from(this.state.contents);
var i = 0;
while(i < _contents.length){
if(_contents[i].id === _id) {
_contents[i] = {id:_id, title:_title, desc:_desc};
break;
}
i = i + 1;
}
this.setState({
contents:_contents,
mode:'read'
});
}.bind(this)}></UpdateContent>
}
이는 _content라는 객체에 this.getReadContent();을 간단히 넣어줘 수정할 수 있게끔 read를 불러온다.
그리고 수정된 내용을 다시 _article에 담을것인데 <UpdateContent data={_contnent} 부분에 data가 어떤 내용인지 기억이나지않아 살펴보니 >
(JSX attribute) data: {
id: number;
title: string;
desc: string;
이런내용이 담겨있었다. 더 공부해야할 부분인듯하다.
아무튼 update버튼을 눌러 read가 수성가능하도록 form이 생성될 때 입력값을 넣고 submit버튼을 눌렀을 때 실행되는 onSubmit을 정의해놓은 내용인데 수정할 content의 _id값과 _title, _desc를 매개변수로 받고
_contents에 객체배열을 복사하여 담은곳에 contents.length만큼 id값을 비교한뒤 매개변수로 받은 _id값과 일치할 때 그 contents를 모두 담고 break;걸어 빠져나온다.
그리고 그 값을 setState로 변경, 변경된 모습을 'read'모드로 확인하는 모습이다.
class UpdateContent extends Component{
constructor(props){
super(props);
this.state = {
id:this.props.data.id,
title:this.props.data.title,
desc:this.props.data.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="/update_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 name="desc" placeholder="description" value={this.state.desc}
onChange={this.inputFormHandler}
></textarea>
</p>
<p>
<input type="submit"></input>
</p>
</form>
</article>
);
}
}
마지막으로 UpdateContent의 Component코드인데 천천히 또 살펴보자
constructor(props){
super(props);
this.state = {
id:this.props.data.id,
title:this.props.data.title,
desc:this.props.data.desc
}
this.inputFormHandler = this.inputFormHandler.bind(this);
}
inputFormHandler(e){
this.setState({[e.target.name]:e.target.value});
}
Component내부에 다시 또 state를 만들어 그 id값과 title, desc값을 this.props.data값으로 모두 줬다.
this.props.date값은 this(UpdateContent인 Component)가 가지고있는 props.data로 이 Component가 가지고있는 id값과 title, desc의 값을 각각 넣어준다는 의미이다.
그리고 중간코드는 inputFormHandler을 쓸때마다 bind(this)를 생략하기 위해 쓴것이고
inputFormHandler(e)정의인데 이는 e.target.value인 이벤트효과로 받은 변수값(즉 update할 내용, 수정할 값들)들을 [e.target.name]에 담는다는건데 이건 js의 새로운 문법이라는데 e.target.title과 e.target.desc를 알아서 찾아주는 문법이라고 한다 !
그후에는 수정할 값들을 받아서 바꾸는onChange()로 안에 inputFormHadler를 넣어줘 그에맞는(e.target.value)값들을 저장할 수 있게 한다.
이로써 생활코딩의 react시간이 끝이났다. 아직 어려운부분이 많아 내가 정리를 하면서도 마음에들지 않는부분도 많았지만 강의를 끝내고 한줄한줄 내가 분석하면서 다시 공부한다는 마음으로 기록해뒀다.