본문 바로가기

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

[생활코딩] React 강의 완강 - 20~21강 update 구현

반응형

20.1강 update 구현

else if (this.state.mode === 'update') {
      var _content = this.getReadContent();
      _article = <UpdateContent data={_content} 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({
          contents: _contents
        });
        console.log(_title, _desc)
      }.bind(this)}></UpdateContent>
    }

여기서 mode === 'Update' 라고 적어서 계속 진행이 안되었다....

 

업데이트 기능은 read 기능과 create 기능이 결합되어 있는 것

update 할려면 create 처럼 폼이 었어야하고 기존의 컨텐츠를 수정 하는 것이기 때문에

read 처럼 기존의 컨텐츠를 불러와서 form에다가 내용을 추가해주는 작업이다.

 

너무 복잡해서 새로운 함수로 쪼개서 분리시키기 + UpdateContent 라고 하는 컴퍼넌트가 실행될 때, 입력 값으로 현재 선택된 콘텐트의 id가 2번인데, 애를 UpdateContent 이 컴퍼넌트에 주입시켜주는 작업을 해보자.

selected_Content_id와 같은 원소를 찾아줘야한다.  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;
        break;
      }
      i = i + 1;
    }
  }
  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) {
        // add content to this.state.contents
        this.max_content_id = this.max_content_id + 1;
        // this.state.contents.push(
        // {id:this.max_content_id, title:_title, desc:_desc}
        // );
        var _contents = this.state.contents.concat(
          { id: this.max_content_id, title: _title, desc: _desc }
        )
        // var newContents = Array.from(this.state.contents);
        // newContents.push({id:this.max_content_id, title:_title, desc:_desc}
        // )
        // this.setState({
        // contents:newContents
        // });
        this.setState({
          contents: _contents
        });
        console.log(_title, _desc)
      }.bind(this)}></CreateContent>
    } else if (this.state.mode === 'update') {
      var _content = this.getReadContent();
      _article = <UpdateContent data={_content} 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({
          contents: _contents
        });
        console.log(_title, _desc)
      }.bind(this)}></UpdateContent>
    }
    return _article;
  }
  render() {
    console.log('App render');
    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>
        {this.getContent()} // 요부분 
      </div>
    );
  }
}

20.2강 update 구현 : form

컴퍼넌트로 주입된 데이터를 기반으로 해서 이 컴퍼넌트에 기본적으로 입력되는 값 셋팅

forms 제어와 관련되어있다.

 

state화

constructor(props){

super(props);

this.state = {

title:thos.props.date.title

}

)

 

inputFormHandler를 사용해서 this.setState, bind(this) 중복제거

 

UpdateContent.js

import React, {Component} from 'react';

class UpdateContent extends Component {
  constructor(props){	
    super(props);
    this.state = {	// props는 readonly이므로 가변적으로 만들기 위해 state화
      title:this.props.data.title,
      desc:this.props.data.desc
    }
    // inputFormHandler 함수 뒤에 붙는 .bind(this)가 중복되므로 미리 설정하여 제거
    this.inputFormHandler = this.inputFormHandler.bind(this);
  }
    inputFormHandler(e){
      // e.target.name으로 이벤트 객체의 name 값인 title / desc 값 가져옴
      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(
                e.target.title.value,
                e.target.desc.value
              );
            }.bind(this)}
          >
              <p>
                <input 
                  type="text" 
                  name="title" 
                  placeholder="title"
                  value={this.state.title}
                  onChange={this.inputFormHandler}	// state를 변경하기 위해 필요
                ></input></p>
              <p>
                <textarea onChange={this.inputFormHandler}
                  name="desc" 
                  placeholder="description" 
                  value={this.state.desc}></textarea>	
                   {/* html과 다르게 value로 기본값 설정 */}
              </p>
              <p>
                <input type="submit"></input>
              </p>
            </form>
        </article>
      )
    }
  }

  export default UpdateContent;

 

20.3강 update 구현 : state 변경

저번강의에서는 props로 들어온 데이터를 state로 만들고 이 state에 값을 각각의 form과 동기화 시켜서 state값을

계속해서 변화시키는 방법을 살펴보았다. 

 

하지만 update를 하려면 어디를 update 할 것인지에 대한 식별자가 필요하다.

 

보통 form에서는 id와 같이 수정할 때, id는 사용자한테 보일 필요가 없기 때문에 히든 form을 쓴다.

존재하지만 눈에 보이지않는 친구. 그럼에도 할 필요가있나?

'JS가 동작하지 않을 때도 여기 있는 코드가 동작하게 한다'가 JS로 우리가 뭔가 만들 때 기본적인 기조이고

다른 용도로 활용될 가능성이 있기 때문에 JS없이도 구현에 충실하는 것이 좋다.

 

#기존

onSubmit 버튼을 눌렀을 때, onSubmit 이벤트가 발생 -> 이 컴퍼넌트로 들어온 this.props.onSubmit을

실행할 때 e.target.title.value, e.target.desc.value 이런식으로 한다.

여기다가 id값까지 주면 금상첨화 =>  state.id, title, desc 로 바꾸기

 <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>

this.max_content_id 는 create 할 때 필요한 것이니 Update 쪽에서는 지워준다.

 

concat은 기존에 있던 데이터를 추가할 때 쓰는 것인데 우리는 지금 수정을 하려고 하니까 복제를 할 것이다.(불변하는, 원본을 바꾸지 않지만 값은 같은 컨텐츠 만들기. 나중에 성능을 튜닝할 때 필요하다)

우리가 수정하려고 하는 배열이나 객체를 수정하려고 할 때는 개를 복제한다. 그리고 복제한 것을 push해서 값을 추가한다. push를 concat한 것.


이렇게 하고 update하면 잘 작동하지만 보통 우리가 알고있는 방식은 그 바뀐 것으로, 상세보기 까지 되는 것. 고로 mode: "update"를 -> "read"로 바꿔주면 된다. selected_conent_id를 방금 우리가 추가한 값 this.max_content_id

로 바꿔준다.

 

Array.from(this.state.contents); 사용

-> 원본을 복사한 새로운 배열이 만들어진다. 이것을 var _contents라는 이름으로 바꾸기

_contents 안에 있는 원소들 하나하나를 뒤져서 id값이 우리가 수정하고자 하는 것과 같은 원소를 찾아야한다.

 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>
    } 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>
    }
    return _article;
  }

while을 써야 list들을 눌렀을 때 값이 뜬다.

i를 1씩 증가시킨다. 만약에 _contents[i]와 우리가 지금 입력받은 id 값이 같다면 우리는 그 객체를 교체해줘야한다.

{id:_id, ....desc:_desc} 이런식으로 한다. 그리고 이걸 했으면 조건 반복문을 할 필요가 없으니까 break를 해주는 것이다.

        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

이제 list에 있는 HTML, CSS, JS를 클릭하고 누르면 잘 바뀌고 수정이 가능하다. Update가 제일 힘들다. read, create를 다 할 줄 알아야하기 때문이다. 

21강 delete 구현

class App extends Component {
  constructor(props) {
    super(props);
    this.max_content_id = 3;
    this.state = {
      mode: 'welcome',
      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' }
      ]
    }
  }

여기서 mode는 맨 처음 로딩화면을 어디로 할 지 맞춰주는 부분. create였던 것을 welcome으로 바꾸기.

 

 

 

 

Contorl 안에 delete버튼이 있다. 이 버튼은 onChangeMode라고 하는 props를 호출하고 있다.

          <li><input onClick={function(e){
            e.preventDefault();
            this.props.onChangeMode('delete');
          }.bind(this)} type="button" value="delete"></input></li>
        </ul>
      );
    }
  }

 

 

그러면 onChangeMode의 function (_mode)라는 값이 delete 로써 호출된다면 삭제 operation 시작된 것.

만약에 _mode가 delete 이면 삭제를 해주고 그렇지 않다면 welcome으로 페이지 전환만 해줘라.

삭제가 시작됐을 때 어떤일이 일어나야 좋을까?

제일 먼저 어떤 일이 일어나야 할까를 알려주면 좋을 것 => confirm 사용

confirm은 앞에 window.를 붙여줘야만 쓸수가 있다.

confirm을 실행 했을 때 사용자가 확인을 누르면 true, 캔슬을 누르면 false가 실행된다.

여기서 우리가 해야할 것은? 

누구를 삭제할 것인가? selcted_content_id 를 통해 알 수 있다.

2번째로 어떤 데이터를 삭제할 것인가는 contents  쪽에서 찾아낼 수 있다. 

while을 사용해서 찾아라.

this.state.contents는 나중에 setState로 들어갈 것이다. 고로 복제를 하면 더욱 좋다 => Array.from 사용

 

_contents[i].id === this.state.selected_content_id와 같다면?

 

 _contents에서 어디서부터 어디까지를 지울 것인가 - > splice를 사용하면 된다. 

우리가 발견한 원소의 id값부터 한개를 지우겠다 하면 _contents의 원본을 바꾼다. 

그 값을 바꿨으면 break를 때려주면 된다. 그 후 setState로 contents의 값으로 _content를 넣는다.

삭제가 잘 됐다면 mode를 welcome으로 바꿔준다. 보여줄게 없으니까!

confirm() 안에다가 'really'를 써주면 경고창 문구가 뜰 것이다. state도 없어졌고 welcome으로 이동했고

alert를 추가해서 삭제가 잘 되었다고 뜨는 문구도 추가해주면 완벽.

 

        <Control onChangeMode={function (_mode) {
          if(_mode === 'delete'){
            if(window.confirm('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>

# Delete를 한 경우 selected_content_id는 삭제된 객체의 id를 가리키고 있기 때문에 바로 Update를 누르게 되면 Uncaught TypeError: Cannot read property 'id' of undefined 에러가 발생하게 됩니다. 그래서 Control의 setState에서 selected_content_id의 값을 수정할 필요가 있을 것 같습니다.

 

#그런데 제가 수업을 들으면서 코드를 조금 변경해서 delete 후에 새로 create 시에는 error가 발생되더군요. 아마 delete 후 "this.max_conetent_id--"를 해줘야 할 거 같습니다. (저같은 경우 filter를 쓴 경우이긴한데 다른 분들도 에러가 나지 않을까 싶네요) 강의해주신 React CRUD 예제만 이해했다면 React를 사용해서 웬만한 웹사이트는 다 구성할 수 있을 것 같네요. 다시 한 번 감사드립니다! 이제 React class vs function style, react router 정주행하러 갑니다.

 

22강 수업을 마치며

immutable

  • 불변성
  • immutable-js
    - 배열과 객체의 대체재
    • 모든 연산이 원본이 복제된 결과 리턴

router

  • 페이지 전환을 할 때마다 네트워크 로딩을 하지 않는 장점이 있지만, url로 페이지를 찾아올 수 없다는 단점
  • react router - url에 따라 컴포넌트가 실행될 수 있도록 도와줌

create-react-app

  • npm run eject
    - 감춰진 create-react-app의 설정을 수정할 수 있음
    • 되돌릴 수 없으므로 주의

redux

  • 기존 react에서는 자식 컴포넌트 / 부모 컴포넌트 사이에 props나 이벤트 버블링 필요
  • redux는 중앙 데이터 저장소에 모든 컴포넌트가 연결되어 있고, 저장소의 내용이 변경되면 관련된 컴포넌트가 변경됨

react server side rendering

  • 서버에서 웹페이지를 완성한 후 클라이언트에 전송하는 방식으로 애플리케이션 구동
    - 초기 구동시간 단축
    • JavaScript 특유의 로딩이 필요없는 특성 유지
    • 검색 엔진 등의 로봇이 html을 읽도록 할 수 있음

react native

  • react 방식으로 네이티브 앱 제작 가능
    - 하나의 코드가 거의 모든 애플리케이션에서 동작 가능'

출처: velog.io/@chez_bono/%EC%83%9D%ED%99%9C%EC%BD%94%EB%94%A9-React-%EC%88%98%EC%97%85%EC%9D%84-%EB%A7%88%EC%B9%98%EB%A9%B0

 

#댓글

  • React Router: URL마다 적당한 컴포넌트를 뿌려줌
  • Redux: 모든 컴포넌트가 공통적으로 쓰는 저장소를 만들어서, 어느 컴포넌트에서도 손쉽게 state를 바꿀 수 있게 해줌 (순수 React로는 상위에서 하위 컴포넌트를 손볼때는 props로 쉽게 가능하지만, 하위에서 상위 state를 바꿀려면 props값으로 function을 넣어야 함)
  • React Native: React와 같은 방법으로 네이티브앱 (iOS, android)을 쉽게 만들 수 있게 해줌
반응형