[FRONT-END]/[REACT]

React 로 일기장 만들기

지기음 2022. 11. 30. 11:18

백엔드를 학습하기 전 , 간단하게 프론트엔드를 경험하기 위해서 react를 학습했다.
생활코딩님의 유튜브 강의를 보다가 책이 한권 필요할 거 같아 생활코딩님의 [생활코딩! 리액트 프로그래밍] 책으로 공부하였다. 전체적으로 초보자들을 위해 쉽게 설명이 되어있지만 예제를 함수형이 아닌 class형으로 진행하다보니 현재 버전과 약간의 차이가 있었다. 
내가 만든 일기장도 class형으로 만들었다. 

일주일정도 react를 공부한 후 일기장 만들기 실습에 들어갔다.

총 소요시간 : 5~6시간 

 

1. 만들고 싶은 페이지 레이아웃 만들기 

이 부분은 카카오 오븐으로 진행하였다. https://ovenapp.io/

 

OvenApp.io

Oven(오븐)은 HTML5 기반의 무료 웹/앱 프로토타이핑 툴입니다. (카카오 제공)

ovenapp.io

만들기 전 생각한 첫 화면

2. react에 들어갈 기능 생각하기 구현 모습 생각하기 
기본적인 CRUD중 delete를 제외한 기능들을 삽입할 예정이다. 

왼쪽에 있는 제목을 누르면 오른쪽 화면에 일기 내용이 뜰 수 있도록 , 또한 밑에는 수정버튼이 있을 수 있도록 만들 예정이다. 

 

3. 만들기 

1)일단 처음 레이아웃을 구성했다. 
왼쪽에 두개의 컴포넌트 오른쪽에 1개의 컴포넌트가 올 수 있도록 CSS를 구성하였다.

.box1{
  width:30%;
  height: 500px;
  float: left;
}
.box2{
  width:30%;
  height: 80px;
  float: left;
}
.box3{
  width:60%;
  height: 500px;
  float: right;
}
body{
  margin-left:2.5%
}
.line{
  line-height: 30px;
  font-size: large;
}

바디태그에 왼쪽 마진을 살짝 넓혀주어서 글이 너무 왼쪽에 붙어있지 않도록 하였다. 


2)제목 컴포넌트 구성 

사실 그냥 컴포넌트 구성을 하지 않고 바로 html로 작성해도 되지만 react에 장점을 살리기 위해 만들었다. 

import React from 'react';
class Title extends React.Component{
  render(){
    return(
      <div className='box2'>
        <h1>JUNHO DIARY</h1>
      </div>
      
    );
  }
}

export default Title;

3) 왼쪽 제목 리스트 구성 

제목 리스트에서 가장 중요한 부분은 리스트를 눌렀을 떄 오른쪽 화면에 일기가 떠야하는 점이다. 따라서 리스트를 눌렀을 떄 state.mode 를 read로 설정해 일기가 뜨게 하는 점이 가장 중요하다 .
마지막엔 일기를 추가할 수 있는 버튼이 필요하다 . 

또한 dateset을 활용해 id값을 넘겨주는 장치도 중요하다.

import React from 'react';
class Contents extends React.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={"/contents/"+data[i].id}
        data-id={data[i].id}
        onClick={function(e){
            e.preventDefault();
            this.props.onChange(e.target.dataset.id);
        }.bind(this)}
        >{data[i].title}</a></li>);
        i=i+1;
    }
    return( 
        <div className='box1'>
        <nav>
            <ul className="line">
                {lists}
                <button onClick={function(e){
                    e.preventDefault();
                    alert("write");
                    this.props.modeChange();
                }.bind(this)}>wirte</button>
            </ul>
        </nav>
        </div>
    );
  }
}

export default Contents;

4)read모드 일기장 
가장 쉽다. 넘어온 props들을 출력해주기만 하면 된다. 
다만 수정이 필요할 때 수정할 수 있도록 fix버튼을 만들어준다 . fix버튼을 누르게 되면 mode가 fix로 바뀐다. 

import React from 'react';
class Diary extends React.Component{
  render(){
    return(
      <div className='box3'>
       <h1>{this.props.title}</h1>
       <h2>{this.props.desc}</h2>
       <button onClick={function(e){
          e.preventDefault();
          this.props.onFix();
       }.bind(this)}>fix diary</button>
      </div>
      
    );
  }
}

export default Diary;

5) 일기쓰기

이부분은 input된 입력값을 app.js에 넘겨주는 것이 가장 중요하다 . submit을 하게 되면 title과 desc값이 전달될 수 있게 함수를 구성하였다. 

import React from 'react';
class WriteDiary extends React.Component{
  render(){
    return(
      <div className='box3'>
        <p>Write Diary</p>
        <form action="/write" method='post' 
        onSubmit={function(e){
          e.preventDefault();
          this.props.onSubmit(
            e.target.title.value,
            e.target.desc.value
          );//greate
        }.bind(this)}>
            <input placeholder='title' name="title"></input><br/><br/>
            <textarea placeholder='write your diary' name="desc" cols = "40" rows = "30"></textarea><br/><br/>
            <button type="submit">submit</button>
        </form>
      </div>
      
    );
  }
}

export default WriteDiary;

6)수정할 떄의 일기장

수정이 가장 어렵다. 단지 값을 가져와서 수정하려고 하면 오류가 뜨기 때문이다 .이 부분을 해결하기 위해서 가져온 값을 state함수에 너어 나중에 값을 변경할 때 setState함수로 변경할 수 있도록 하는것이 가장 중요하다 .

import React from 'react';
class UpdateDiary extends React.Component{
  constructor(props){
    super(props);
    this.state = {
      title : this.props.title,
      desc : this.props.desc,
    }
  }
  render(){
    return(
      <div className='box3'>
        <p>Update Diary</p>
        <form action="/update" method='post' 
        onSubmit={function(e){
          this.props.onSubmit(
            e.target.title.value,
            e.target.desc.value
          );
        }.bind(this)}>
            <input placeholder='title' name="title" value={this.state.title} onChange={function(e){
              this.setState({title:e.target.value});
            }.bind(this)}></input><br/><br/>
            <textarea placeholder='write your diary' name="desc" cols = "40" rows = "30" value={this.state.desc} onChange={function(e){
              this.setState({desc:e.target.value});
            }.bind(this)}></textarea><br/><br/>
            <button type="submit">submit</button>
        </form>
      </div>
      
    );
  }
}

export default UpdateDiary;

7)마지막 구현부 정리 
이부분은 mode에 따라 달라지는 화면들이 나오는 것이 가장 중요하다 .

import React from 'react';
import Title from './Components/Title';
import Contents from './Components/Contents';
import './App.css';
import Diary from './Components/Diary';
import WriteDiary from './Components/WriteDiary';
import UpdateDiary from './Components/UpdateDiary';

class App extends React.Component{
  constructor(props){
    super(props);
    this.max_id =3;
    this.state = {
      selected_content_id : 2,
      mode : 'read',
      mode : 'write',
      contents:[
        {id:1 ,title:"2022/11/01", desc:"contentsssss"},
        {id:2, title:"2022/11/03", desc:"ccccccccccc"},
        {id:3, title:"2022/11/05", desc:"aaaaaaaaa"}
      ]
    }
  }

    
  render(){
    var _title,_desc,_article =null;
    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 = data.title;
          _desc = data.desc;
          _article = <Diary onFix={function(e){
            this.setState({
              mode :'fix'
            });
          }.bind(this)} title={_title} desc={_desc}></Diary>
          break;
        }
        i++;
      }

    }
    else if(this.state.mode ==='write'){
      _article = <WriteDiary onSubmit={function(_title,_desc){
        this.max_id = this.max_id+1;
        var _contents = Array.from(this.state.contents);
        _contents.push({id:this.max_id,title:_title,desc:_desc});
        this.setState({
          contents : _contents,
          mode : 'read',
          selected_content_id : this.max_id
        })
      }.bind(this)}></WriteDiary>
    }
    else if(this.state.mode ==='fix'){
      var i = 0;
      while(i<this.state.contents.length){
        var data = this.state.contents[i];
        if(data.id === this.state.selected_content_id){
          _title = data.title;
          _desc = data.desc;
          break;
        }
        i++;
      }
      _article = <UpdateDiary title={_title} desc={_desc} onSubmit={function(_title,_desc){
        var _contents = Array.from(this.state.contents);
        _contents[i].title = _title;
        _contents[i].desc = _desc;
          this.setState({
          contents : _contents,
          mode : 'read'
        })
      }.bind(this)}></UpdateDiary>
    }
    return(
    <>
     <Title></Title>
     {_article}
     <Contents onChange={function(id){
      this.setState({
        mode:'read',
        selected_content_id:Number(id)
      });
     }.bind(this)} 
     modeChange={function(){
      this.setState({
        mode:'write'
      })
     }.bind(this)}
     data={this.state.contents}></Contents>
     
    </>
    );
  }
}


export default App;

8) 실제 구현장면 

 

9) 후기 

1. 프로젝트를 시작하기전에 더 많은 계획이 필요하다. 예를 들어 mode를 변경하는 것을 함수로 만들어 모듈화를 시켰다면 더 깔끔한 코딩이 되었을 것이다. 

2. class 형보다 함수형이 참고할 만한 자료가 많고 최신형이다. 따라서 react를 공부할 때 함수형으로 다시 공부해야할 필요성이 있다.

3. git을 잘써야 한다.  원인을 찾을 수 없는 오류가 나왔을 때 이전 버전으로 돌아가고 싶을 때가 있다. 버전관리를 잘해놨으면 더 빠르게 만들었겠다. 

+) 다 만들고 블로그에 정리하려니 힘들다. 다음번엔 기능 하나 하나씩 블로그에 정리 해보도록 해야겠다. 

 

다음에 공부할 것 : SPRING