textarea안에 적은 내용만큼, 또는 Enter키 누를 때마다 자동으로 높이가 조절되는 textarea 기능을 만들어보겠습니다.

 

 

먼저 body안에 테스트할 아래 태그와 적당한 스타일을 추가해줍니다.

<textarea>반지의 제왕은 톨킨이 창조한 세계인 중간계의 제3시대 말을 배경으로, 인간족과 다른 종족들(호빗, 요정, 난쟁이, 오크 등)의 이야기를 다루고 있다.
  이야기는 암흑 군주 사우론이 만든 절대 반지(the One ring)를 중심으로 조용한 마을인 샤이어서부터 중간계를 지나며
  반지전쟁의 진행과정을 주인공인 프로도의 눈으로 보인다. 이어지는 6개의 부록에서는 중간계의 역사적, 언어학적 배경을 담고 있다.
  톨킨의 다른 책과 같이, 반지의 제왕은 톨킨이 관심을 가지고 있던 북유럽 신화에서 많은 부분을 차용하였다.
  이 외에도 제1차 세계 대전에서의 경험[4] 이나, 기독교(로마 가톨릭교회), 산업화도 톨킨의 세계에 영향을 주었다.
  반지의 제왕은 현대 판타지 소설에 큰 영향을 끼친 것으로 인식되는데, 톨키니안(Tolkienian) 이나 톨키니스크(Tolkienesque) 같은 단어들이
  옥스퍼드 영어 사전에 등재되었다.
</textarea>
textarea {width:50%; padding:20px 20px 5px; border:1px solid #ddd; background:#fcfcfc; resize:none; overflow-y:hidden; font-family:"malgun gothic";}

 

 

순수 자바스크립트로 textarea auto resize height

/* vanilla javascript */
document.addEventListener("DOMContentLoaded", function() {
  var $textarea = document.querySelector("textarea");
  $textarea.addEventListener('keyup', function(e) {
    this.style.height = "auto";
    this.style.height = this.scrollHeight + "px";
  });
  $textarea.dispatchEvent(new Event('keyup'));
});

 

 

Jquery를 이용한 textarea auto resize height

/* jQuery */
$(document).ready(function() {
  $('textarea').on( 'keyup', function (e){
    $(this).css('height', 'auto');
    $(this).height(this.scrollHeight);
  });
  $('textarea').keyup();
});

 

 

코드하단에 textarea에 걸어둔 이벤트를 한번 먼저 호출해주는 이유는 브라우저에서 기본 지정된 높이 또는 style에서 지정된 높이를 로딩시 컨텐츠내용만큼 다시 조정하기위해서입니다. 로딩시 textarea에 들어갈 text가 없다면 굳이 안넣어줘도 됩니다.

 

그리고 css로 height를 auto로 먼저 잡아주는 이유가 있는데요. 기존 높이를 auto로 먼저 잡아주지 않으면 textarea 높이를 재세팅할 때 내용 한줄한줄 만큼이 아닌 기존 height를 반영하여 확확 커지기 때문입니다. 왜 이렇게 동작하게 됬는지는 잘 모르겠습니다. 일종의 버그인지도 모르겠네요.

 

 

아래의 배열데이터를 테이블로 출력할 때 순수자바스크립트와 jQuery로 각각 어떻게 표현하는지 비교해보겠습니다.

var data = [
    ["내용1_1", "내용1_2"],
    ["내용2_1", "내용2_2"],
    ["내용3_1", "내용3_2"],
    ["내용4_1", "내용4_2"]
];

 

준비된 테이블형태는 다음과 같고 tbody안에 <tr><td>내용1_1</td><td>내용1_2</td></tr>과 같은 형식으로 출력되도록 할 것입니다.

<table class="list">
    <thead>
        <th>항목1</th>
        <th>항목2</th>
    </thead>
    <tbody>
    </tbody>
</table>

 

 

예상 결과화면은 다음과 같습니다.

 

 

참고로 스타일은 생략해도되지만 전 대략적으로 잡아주겠습니다.

<style>
h3 {margin-bottom:10px;}
table {width:30%; margin-bottom:30px; border-collapse:collapse;}
table th, table td {border:1px solid #ddd;}
</style>

 

 

 

순수 자바스크립트로 테이블목록 출력

/* vanilla javascript */
document.addEventListener("DOMContentLoaded", function() {
    var $listTbody = document.querySelector(".list tbody");
    data.forEach(function(val) {
        $listTbody.innerHTML +="<tr><td>" + val[0] + "</td><td>" + val[1] + "</td></tr>";
    });
});

 

 

jQuery로 테이블목록 출력

/* jQuery */
$(document).ready(function() {
    var $listTbody = $(".list tbody");
    data.forEach(function(val) {
        $listTbody.append("<tr><td>" + val[0] + "</td><td>" + val[1] + "</td></tr>");
    });
});

 

 

간단한 예제라 그런지 순수 자바스크립트와 jQuery간의 코드분량차이가 많이 나진 않습니다. 다만 주의할 것은 각 속성또는 메서드마다 서포트브라우저가 다르므로 하위호환성이 필요한 경우 잘 확인을 해주셔야 합니다. (ie지원 종료전까지 참고요망)

 

속성/메서드 ie호환 버전/문법표현변화
addEventListener ie9이상
querySelector ie8이상
forEach ie9이상
innerHTML ie4이상 / Dom요소추가 가능: ie10이상

 

REST API

 

서버와 통신하는 방식 중 한 가지로 http메서드를 사용하여 데이터를 요청/전송합니다. 기존에 많이 사용하던 SOAP API 의 경우 서비스 인터페이스를 이용해 서버에 접근했다면, REST는 인터넷 식별자(URI)와 HTTP 프로토콜을 이용해서 접근하는 것이 특징이며 사용법이 단순하여 높은 보안수준을 요구하는 작업이 아닐 경우 일반적으로 많이 선호되는 통신방법입니다 . 데이터포맷은 브라우저 호환성이 좋은 JSON을 사용하며 resource, method, message로 구성됩니다.

 

 

 

 

 

REST API 메소드

 

종류 용도 사용예시 사용예시 해석
GET 데이터 조회 GET/users/1 (users의 1번 데이터 조회)
POST 데이터 등록 POST/users (users 등록)
PUT 데이터 수정 PUT/users/1 (users의 1번 데이터 수정)
DELETE 데이터 삭제 DELETE/users/1 (users의 1번 데이터 삭제)

 

 

 

 

요청한 Data를 React에서 관리하는 기본방법

 

useState, useEffect로 데이터를 로딩/저장하여 사용하며, 데이터요청 이후의 요청결과, 로딩상태, 에러처리가 관리대상이 됩니다.

 

 

 

 

 

REST API로 쉽게 Ajax요청하도록 도와주는 라이브러리 - Axios

 

//사용예시

axios.get('users/1');  //조회

axios.post('users', {  //등록
  name: 'anne',
  email: 'anne@gmail.com'
});

요청시 promise를 반환합니다.

 

 

 

 

 

'React.js > React 관련지식' 카테고리의 다른 글

React주석과 JSX주석처리  (0) 2020.09.13

React코드 주석

javascript와 동일하게 한 줄주석은 //로, 여러 줄은 /* */로 처리합니다.

// singleline comments
componentDidMount() {
  //console.log("test");
    this._getProducts();
};


// multiline comments
componentDidMount() {
  /*console.log("test");
    this._getProducts();*/
};

 

 

React JSX코드 주석

javascript의 여러줄 주석을 {}로 감싸준 형태로 사용합니다.

{/*<div className="test">
     주석연습
</div>*/}

 

 

'React.js > React 관련지식' 카테고리의 다른 글

REST API란? (& React)  (0) 2020.10.26

React작업시 클라이언트와 서버를 각각 실행해줘야하는 불편함을 해결하기 위해 필요한 모듈을 설치해보겠습니다.

 

작업진행순서

  • nodemon과 nodemon concurrently모듈 설치
  • package.json 설정추가
  • 클라이언트 디렉토리에서 명령어 입력후 실행확인

 

 

클라이언트와 서버 동시실행 모듈 설치

먼저 nodemon모듈을 설치해줍니다.

npm install nodemon -g
yarn global add nodemon

 

그리고나서 nodemon concurrently를 설치해줍니다.

npm install nodemon concurrently --save-dev
yarn add nodemon concurrently --dev

 

 

 

package.json에서 scripts항목 추가

"scripts": {
    "start": "node scripts/start.js",
    "build": "node scripts/build.js",
    "server": "nodemon server/server.js",
    "dev": "concurrently \"nodemon server/server.js\" \"node scripts/start.js\"",
    "test": "node scripts/test.js"
  },

 

 

 

React프로젝트위치(클라이언트 디렉토리)에서 실행명령어 입력

npm run dev
yarn dev

 

Sequelize를 사용해 테이블명.js를 만들면 기본적으로 DB에 table생성시 '테이블명s'로 생성이 됩니다.

그런데 기존의 table명을 그대로 사용하고 싶고 끝에 's'표기를 사용하고 싶지 않다면 models/테이블명.js추가시 설정을 추가해줍니다.

 

module.exports = (sequelize, DataTypes) => {
    return sequelize.define(
        'sample1', 
        {
            name: {
                type: DataTypes.STRING(50),
                allowNull: true
            },
            email: {
                type: DataTypes.STRING(50),
                allowNull: true
            }
        },
        {
            charset: 'utf8',
            collate: 'utf8_general_ci',
            timestamps: false,
            freezeTableName: true,
        }
    )
};

 

테이블명, 데이터항목정의 부분 다음 기타설정 부분에 아래 코드를 추가해줍니다.

freezeTableName: true,

데이터삭제를 위한 기본준비

먼저 App.js에서 DB에 저장된 전체 목록을 화면에 보여주고 각 레코드마다 삭제버튼을 추가해줍니다.

import React, { Component } from "react";
import axios from 'axios';


class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      sample1List : [],
    }
  };

  componentDidMount() {
    this._getData();
  }

  _getData = async () => {
    const res = await axios.get('/get/data');
    this.setState({ 
      sample1List : res.data
    })
  }

  // 이후 추가할 코드영역
  
  render() {
    const { sample1List } = this.state;

    return(
      <div className='App'>
        <h3>Hello, You are testing React!</h3>

        <h4> Sample1 List </h4>

        {sample1List.length !== 0 ? 
        sample1List.map( (el, key) => {
          return(
            <div key={key}>
              <span> ID: {el.id} </span>/
              <span> NAME: {el.name} </span>/
              <span> EMAIL: {el.email} </span>
              <button onClick={() => this._delete(el)}>delete</button>
            </div>
          )
        })
        : <div>데이터가 없습니다.</div>}

      </div> 
    )
  };
};


export default App;

 

그리고 server.js에서 전체목록을 가져오기위한 코드를 넣어줍니다.

 

const express = require('express');
const app = express();

const sequelize = require('./models').sequelize;
const bodyParser = require('body-parser');

sequelize.sync();

app.use(express.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());

const {
    Sample1,
    Sequelize: { Op }
  } = require('./models');
sequelize.query('SET NAMES utf8;');

app.get('/get/data', (req, res) => {
   Sample1.findAll()
    .then( result => { res.send(result) })
    .catch( err => { throw err })
})

// 이후 추가할 코드영역

const PORT = process.env.PORT || 4000;
app.listen(PORT, () => {
    console.log(`Server On : http://localhost:${PORT}/`);
})

 

 

 

 

데이터 삭제 - destroy({ where : {삭제대상} })

App.js에서 목록마다 추가된 삭제버튼 클릭시 삭제요청코드를 추가해줍니다.

 

  _delete = async (el) => {
    const remove = window.confirm(el.name + '을 삭제하시겠습니까?');

    if(remove) {
      const target = { id : el.id }
      const res = await axios('/delete/data', {
        method : 'POST',
        data : { 'delete' : target },
        headers: new Headers()
      })
      
      if(res.data) {
        alert('데이터를 삭제했습니다.')
        return window.location.reload();
      }
    }
  }

 

server.js에서 '/delete/data' 요청을 처리하기 위한 코드를 넣어줍니다.

 

app.post('/delete/data', (req, res) => {
    Sample1.destroy({
        where : { id : req.body.delete.id }
    })
    .then( res.sendStatus(200) )
    .catch( err => { throw err })
})

 

서버와 React를 실행하여 화면에서 확인해봅니다.

 

처음 로딩화면

 

마지막 목록 삭제버튼 클릭

 

삭제 완료된 화면

한가지 데이터 변경하는 방법, 여러개의 데이터를 변경하는 법을 알아보겠습니다. 

데이터변경 역시 조회와 작업내용은 비슷합니다. 먼저 변경테스트를 위한 기본코드를 준비하고 App.js와 server.js에 각각 화면용 렌더링/데이터요청 코드와 데이터처리코드를 추가해주겠습니다.

 

 

 

데이터변경을 위한 기본준비

먼저 App.js에서 DB에 저장된 전체 목록을 화면에 보여주고 각 레코드마다 수정버튼을 추가해줍니다. 

 

import React, { Component } from "react";
import axios from 'axios';


class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      sample1List : [],
    }
  };

  componentDidMount() {
    this._getData();
  }

  _getData = async () => {
    const res = await axios.get('/get/data');
    this.setState({ 
      sample1List : res.data
    })
  }

  // 이후 추가할 코드영역
  
  render() {
    const { sample1List } = this.state;

    return(
      <div className='App'>
        <h3>Hello, You are testing React!</h3>

        <h4> Sample1 List </h4>

        {sample1List.length !== 0 ? 
        sample1List.map( (el, key) => {
          return(
            <div key={key}>
              <span> ID: {el.id} </span>/
              <span> NAME: {el.name} </span>/
              <span> EMAIL: {el.email} </span>
              <button onClick={() => this._modify(el)}>modify</button>
            </div>
          )
        })
        : <div>데이터가 없습니다.</div>}
		
        <button onClick={this._modifyMulti}>modify 여러개</button>
      </div> 
    )
  };
};


export default App;

 

위의 onClick시 실행될 this._modify(el)부분은 해당하는 sample1List의 각 목록(el)을 인자로 넘겨 함수내부에서 해당하는 목록에 대한 값을 수정해주기 위함입니다. (_modify와 _modifyMulti함수는 이후에 추가해주겠습니다.)

server.js도 아래와 같이 코드를 준비해줍니다.

 

const express = require('express');
const app = express();

const sequelize = require('./models').sequelize;
const bodyParser = require('body-parser');

sequelize.sync();

app.use(express.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());

const {
    Sample1,
    Sequelize: { Op }
  } = require('./models');
sequelize.query('SET NAMES utf8;');

app.get('/get/data', (req, res) => {
   Sample1.findAll()
    .then( result => { res.send(result) })
    .catch( err => { throw err })
})

// 이후 추가할 코드영역

const PORT = process.env.PORT || 4000;
app.listen(PORT, () => {
    console.log(`Server On : http://localhost:${PORT}/`);
})

 

 

 

한 개의 데이터변경 - update({ 변경할 값 }, { where : { 변경대상 }})

아래 코드는 name을 수정하기 위한 코드입니다.

App.js에서 _modify가 호출되면 prompt창을 통해 변경할 name값을 저장(변경할 대상을 확인하기 위해 id값을 함께 저장)하여 서버에 전송합니다. 수정완료응답이 도착하면 변경된 리스트를 다시 화면에 표시해주겠습니다.

_modify = async (el) => {
    const newName = prompt(el.name + '의 변경할 이름을 입력해주세요.')

    if(newName !== null) {
      const dataToModify = {
        newName : newName,
        id : el.id
      }

      const res = await axios('/modify/data', {
        method : 'POST',
        data : { 'modify' : dataToModify },
        headers: new Headers()
      })

      if(res.data) {
        console.log(res.data[0]);
        alert('이름이 수정되었습니다.')
        return window.location.reload();
      }
    }
  }

 

server.js에서 '/modify/data'에 대한 요청을 처리할 코드를 넣어줍니다.

 

app.post('/modify/data', (req, res) => {
    Sample1.update({ name : req.body.modify.newName }, {
        where : { id : req.body.modify.id }
    })
    .then( result => { res.send(result) })
    .catch( err => { throw err })
})

 

서버와 react를 실행하여 브라우저에서 확인해봅니다.

 

처음 로딩시 화면

 

마지막 목록의 modify버튼을 클릭하여 이름 수정요청
수정된 이름이 적용됨

 

 

 

여러 개의 데이터 변경 - update({ 변경할 값 }, { where : {[Op.or] : [ 변경대상, 변경대상..]} }) 

id와 name으로 변경할 2개의 대상을 넘겨 모두 같은 이름으로 수정하는 작업을 테스트해보겠습니다.

App.js에서 아래 코드를 추가해줍니다. 'modify 여러개' 버튼 클릭시 변경할 2개의 대상 id/이름을 입력받습니다.

 

_modifyMulti = async (el) => {
    const targetId = prompt('변경할 대상 ID를 입력해주세요.')
    const targetName = prompt('변경할 대상 이름을 입력해주세요.')
    const newName = prompt('변경할 대상들의 새로운 이름을 입력해주세요.')

    if(newName !== null) {
      const dataToModify = {
        targetId : targetId,
        targetName : targetName,
        newName : newName
      }

      const res = await axios('/modify/multiData', {
        method : 'POST',
        data : { 'modify' : dataToModify },
        headers: new Headers()
      })

      if(res.data) {
        console.log(res.data[0]);
        alert('요청하신 대상들의 이름이 수정되었습니다.')
        return window.location.reload();
      }
    }
  }

 

server.js에서도'/modify/multiData'에 대한 처리코드를 넣어줍니다.

 

app.post('/modify/multiData', (req, res) => {
    Sample1.update({ name : req.body.modify.newName }, {
        where : { [Op.or]: [{ id : req.body.modify.targetId }, { name : req.body.modify.targetName }]}
    })
    .then( result => { res.send(result) })
    .catch( err => { throw err })
})

 

서버를 재실행하여 id : 1번과 name : anne4인 대상의 이름을 anne10으로 수정요청했습니다.

 

이번에는 브라우저화면에서 특정(sample1.js - sample1s in DB) table의 전체데이터 조회, 키워드로 해당데이터 조회, 여러개 키워드로 조회하는 방법을 알아보겠습니다. (기본 다른 세팅은 이전 글에서 설명한 것으로 이미 준비되었다고 가정하고 진행하겠습니다.)

 

진행할 작업 내용:

  • 사용할 데이터를 위한 state요소와 구성할 기본화면 준비
  • App.js에서 server로 데이터요청을 위한 코드 추가
  • server/server.js에서 각 요청url에 대한 처리코드 추가

 

 

 

데이터조회 테스트를 위한 기본준비 

state에서 관리할 name, email, sample1List를 준비하고 render될 화면에서는 데이터목록이 있을 때와 없을 때의 코드를 넣어줍니다. 받아올 데이터는 배열형태로 전달되기 때문에 map메소드를 사용했으며 Search버튼과 ListAll버튼의 실행할 함수는 진행과정에서 정의해주겠습니다. 

 

//App.js

import React, { Component } from "react";
import axios from 'axios';


class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      name : '',
      email : '',
      sample1List : [],
    }
  };

  componentDidMount() {
  }
  
  // 이후 추가할 코드 영역
  
  _nameUpdate(e) {
    this.setState({ name : e.target.value })
  }
  _emailUpdate(e) {
    this.setState({ email : e.target.value })
  }
  
  render() {
    const { sample1List } = this.state;

    return(
      <div className='App'>
        <h3>Hello, You are testing React!</h3>

        <h4> Sample1 List </h4>

        <input type='text' maxLength='10' placeholder='검색키워드(name)' onChange={(e) => this._nameUpdate(e)} />
        <input type='text' maxLength='20' placeholder='검색키워드(email)' onChange={(e) => this._emailUpdate(e)}/>
        <button onClick={this._getKeywordData}>Search</button>
        <button onClick={this._getData}>ListAll</button>

        {sample1List.length !== 0 ? 
        sample1List.map( (el, key) => {
          return(
            <div key={key}>
              <span> ID: {el.id} </span>/
              <span> NAME: {el.name} </span>/
              <span> EMAIL: {el.email} </span>
            </div>
          )
        })
        : <div>데이터가 없습니다.</div>}

      </div> 
    )
  };
};


export default App;
//server/server.js

const express = require('express');
const app = express();

const sequelize = require('./models').sequelize;
const bodyParser = require('body-parser');

sequelize.sync();

app.use(express.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());

const {
    Sample1,
    Sequelize: { Op }
  } = require('./models');
sequelize.query('SET NAMES utf8;');

// 이후 추가할 코드 영역

const PORT = process.env.PORT || 4000;
app.listen(PORT, () => {
    console.log(`Server On : http://localhost:${PORT}/`);
})

 

(목록을 보여주기 위해 먼저 DB table에 데이터가 있는지 확인해주세요.)

지금 상태에서 서버와 react를 실행하면 화면에서 다음과 같이 나옵니다.

 

 

 

 

전체데이터 조회 - findAll()

ListAll버튼시 전체데이터를 요청하기 위해 App.js에 아래 코드를 추가해줍니다. 처음 화면의 모든 요소가 mount됬을 때에도 전체목록을 보여줄 것이므로componentDidMount()에도 전체목록 실행함수를 넣어줍니다.

 

  componentDidMount() {
    this._getData();
  }

  _getData = async () => {
    const res = await axios.get('/get/data');
    this.setState({ 
      sample1List : res.data
    })
  }

 

그리고 server/server.js에서 요청받은 '/get/data'에 대한 코드를 넣어줍니다.

 

app.get('/get/data', (req, res) => {
   Sample1.findAll()
    .then( result => { res.send(result) })
    .catch( err => { throw err })
}) 

 

위의 findAll()은 'SELECT FROM * sample1s'의 쿼리와 동일합니다.

그 다음 서버를 재실행하여 브라우저화면에서 잘 동작하는지 확인합니다.

 

 

 

 

키워드로 데이터검색 조회 - findAll( where : {xxx : yyy} )

이번에는 name에서 입력한 키워드로 데이터를 조회해보겠습니다. App.js에서 위에 추가한 코드에 이어 다음 코드를 넣어줍니다. 

 

  _getKeywordData = async() => {
    const res = await axios('/get/keywordData', {
      method : 'POST',
      data : { 
        'name' : this.state.name
     },
      headers: new Headers()
    });
    this.setState({ 
      sample1List : res.data
    })
  }

 

server.js에도 마찬가지로 아래 코드를 넣어주고 서버를 재실행합니다.

findAll({ where : {...}})은 'SELECT FROM * sample1s WHERE name LIKE 키워드'와 동일합니다.

 

app.post('/get/keywordData', (req, res) => {
    Sample1.findAll({
        where: { name : req.body.name }
    })
    .then( result => { res.send(result) })
    .catch( err => { throw err })
})

 

 

여러개 키워드로 데이터 조회 - findAll({ where: {[Op.or] : [{xxx : yyy}, {xxx : yyy}]} })

name과 email키워드로 데이터를 검색하는 방법을 알아보겠습니다.

App.js에서 아래의 함수를 넣어주고 검색버튼 클릭시 새로추가한 함수를 호출하도록 onClick시 함수명을 변경합니다.

 

  _getMultiKeywordData = async() => {
    const res = await axios('/get/multiKeywordData', {
      method : 'POST',
      data : { 
        'name' : this.state.name,
        'email' : this.state.email
     },
      headers: new Headers()
    });
    this.setState({ 
      sample1List : res.data
    })
  }
<button onClick={this._getMultiKeywordData}>Search</button>

 

그리고나서 '/get/multiKeywordData'에 대한 요청처리를 위한 코드를 server.js에 추가합니다.

 

app.post('/get/multiKeywordData', (req, res) => {
    Sample1.findAll({
        where: { [Op.or]: [{ name : req.body.name }, { email : req.body.email }] }
    })
    .then( result => { res.send(result) })
    .catch( err => { throw err })
})

 

Op.or은 Sequelize에서 or연산자로 데이터를 조회하기 위한 메소드입니다. or(또는)이므로 name과 email중 한개만 입력해도 해당리스트가 조회됩니다.  

그럼 서버를 재실행하여 브라우저에서 확인해보겠습니다.

 

 

 

한 개의 데이터만 조회 - findOne( where : {xxx : yyy} )

findOne은 where조건에 따라 table레코드를 한개만 가져오는 메소드입니다. findAll로 가져올 때랑 다른 점은 findAll의 경우 배열형태로 데이터목록을 담아보내지만 findOne은 객체형태로 보낸다는 점입니다. 그래서 App.js에서 setState를 할때 sample1List를 배열형태로 한번 감싸서 코드를 작성해줍니다.

App.js에서 키워드는 name값으로 하여 아래 함수를 추가해줍니다.

 

  _getKeywordSingleData = async() => {
    const res = await axios('/get/keywordSingleData', {
      method : 'POST',
      data : { 
        'name' : this.state.name
     },
      headers: new Headers()
    });
    this.setState({ 
      sample1List : [res.data]
    })
  }
<button onClick={this._getKeywordSingleData}>Search</button>

 

server.js에도 실행코드를 추가하고 서버를 재실행합니다.

 

app.post('/get/keywordSingleData', (req, res) => {
    Sample1.findOne({
        where: { name : req.body.name }
    })
    .then( result => { res.send(result) })
    .catch( err => { throw err })
})

 

브라우저에서 확인하면 모든 리스트의 공통키워드인 단어로 검색해도 첫번째 1개의 레코드만 출력됩니다.

 

브라우저 화면에서 폼태그로 입력된 값을 DB의 sample1s테이블(컬럼 : id, name, email)에 추가하는 방법을 알아보겠습니다.

 

진행할 작업내용 :

  • 화면단에서 보낸 데이터를 서버에서 읽을 수 있도록 body-parser모듈 설치
  • server/models/index.js에 대상table(sample1 - sample1s in DB)이 정의되었는지 확인
  • server/server.js에 sample1s테이블(from DB)을 서버로 불러와 읽을 수 있도록 코드 추가
  • server/server.js에 정해진 URI로 보내온 데이터를 DB에 저장하는 코드 추가
  • App.js에 폼태그화면 구성과 버튼클릭시 setState된 데이터를 서버로 전송하는 코드 작성
  • 최종 작업된 화면에서 데이터전송하여 DB저장여부 확인 

 

 

 

body-parser모듈 설치

npm install body-parser
yarn add body-parser

 

설치완료 후 server/server.js에 body-parser을 불러서 적용하는 코드를 넣어줍니다.

 

const express = require('express');
const app = express();

const sequelize = require('./models').sequelize;
const bodyParser = require('body-parser');

sequelize.sync();

app.use(express.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());

const PORT = process.env.PORT || 4000;
app.listen(PORT, () => {
    console.log(`Server On : http://localhost:${PORT}/`);
})

 

 

 

models/index.js에서 데이터를 추가할 table정의

 

models/index.js의 전체 코드입니다.

 

'use strict';

const path = require('path');
const Sequelize = require('sequelize');
const env = process.env.NODE_ENV || 'development';
const config = require(path.join(__dirname, '..', 'config', 'db.json'))[ env ];
const db = {};

let sequelize = new Sequelize(
    config.database,
    config.username,
    config.password,
    config,
    {
      define: {
        charset: 'utf8',
        collate: 'utf8_general_ci'
      }
    }
  );
  
    db.sequelize = sequelize;
    db.Sequelize = Sequelize;

    db.sequelize
    .authenticate()
    .then(() => {
        console.log('Connection has been established successfully.');
    })
    .catch(err => {
        console.log('Unable to connect to the database: ', err);
    });

    db.Sample1 = require('./sample1')(sequelize, Sequelize);

db.secret = '(9*)5$&!3%^0%^@@2$1!#5@2!4';
module.exports = db;

 

 

 

 

DB의 대상table을 연결하는 코드를 server/server.js에 추가

bodyParser을 사용하는 코드 아래에 Sample1테이블을 읽어오는 코드를 추가합니다.

 

const {
    Sample1,
    Sequelize: { Op }
  } = require('./models');
sequelize.query('SET NAMES utf8;');

 

 

 

 

지정된 URI로 데이터를 받아 DB에 저장하는 코드 추가

server/server.js에서 위에 추가한 코드부분 아래 post로 받은 데이터를 서버콘솔에서 확인하고 DB에 추가하는 코드를 넣어줍니다.

 

app.post('/add/data', (req, res) => {
    console.log(req.body);

    Sample1.create({
        name : req.body.name,
        email : req.body.email
    })
    .then( result => {
        res.send(result)
    })
    .catch( err => {
        console.log(err)
        throw err;
    })
})

 

 

최종 수정된 server.js파일의 코드입니다.

 

const express = require('express');
const app = express();

const sequelize = require('./models').sequelize;
const bodyParser = require('body-parser');

sequelize.sync();

app.use(express.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());

const {
    Sample1,
    Sequelize: { Op }
  } = require('./models');
sequelize.query('SET NAMES utf8;');

app.post('/add/data', (req, res) => {
    console.log(req.body);

    Sample1.create({
        name : req.body.name,
        email : req.body.email
    })
    .then( result => {
        res.send(result)
    })
    .catch( err => {
        console.log(err)
        throw err;
    })
})

const PORT = process.env.PORT || 4000;
app.listen(PORT, () => {
    console.log(`Server On : http://localhost:${PORT}/`);
})

 

 

 

화면구성 및 form데이터 전송 코드 추가

다음 코드의 내용을 해석해보면 화면에 render되는 폼에서 각각의 input값이 변경될 때마다 _nameUpdate()와 _emailUpdate()가 호출되어 state에 준비된 name과 email의 값을 담아줍니다. 그리고 Add버튼을 클릭하면 _addData가 호출되어 state에 저장된 값을 post로 서버에 보내게 됩니다.

 

import React, { Component } from "react";
import axios from 'axios';


class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      name : '',
      email : ''
    }
  };

  _addData = async(e) => {
    const { name, email } = this.state;
    e.preventDefault();

    const res = await axios('/add/data', {
      method : 'POST',
      data : { 
        'name' : name,
        'email' : email
     },
      headers: new Headers()
    });

    if(res.data) {
      alert('데이터를 추가했습니다.');
      return window.location.reload();
    }
  }

  _nameUpdate(e) {
    this.setState({ name : e.target.value })
  }
  _emailUpdate(e) {
    this.setState({ email : e.target.value })
  }

  render() {
    return(
      <div className='App'>
        <h3>Hello, You are testing React!</h3>
        <form method='POST' onSubmit={this._addData}>
          <input type='text' maxLength='10' placeholder='name' onChange={(e) => this._nameUpdate(e)}/>
          <input type='text' maxLength='20' placeholder='email' onChange={(e) => this._emailUpdate(e)}/>
          <input type='submit' value='Add' />
        </form>
      </div>
    )
  };
};


export default App;

 

 

 

 

브라우저화면에서 데이터추가 요청 및 DB에 추가여부 확인

이제 서버와 react를 시작(또는 재시작)하여 잘 동작되는지 여부를 확인합니다.

 

 

서버콘솔에 데이터가 잘 들어왔네요.

 

 

DB에도 데이터가 잘 저장되었습니다.

 

+ Recent posts