Express에서 DB(MySQL)데이터 가져와 Select Option 구성하기

TEO·2021년 2월 1일
2

저번에 DB(MySQL)에 호텔 리뷰 데이터를 csv파일로 import하여 저장했습니다. 추가적으로 검색기능을 활용하기 위해 다음과 같이 호텔 이름을 모아둔 엑셀파일을 따로 만들어 다시 MySQL의 다른 table에 저장했습니다.

이제 이 hotel_name이란 테이블을 가지고 서버에서 해당 쿼리를 연결하여 데이터를 요청하면 보내줄 수 있게 해줄 겁니다.
express는 mysql모듈을 쉽게 사용할 수 있습니다.

MySQL 모듈 다운

일단 MySQL을 react에서 다운받습니다.

$ npm install mysql

Express server.js

이제 server.js를 수정해줍니다.
기존의 것에다가 추가하는 방식으로 코드 작성할 겁니다.
제일 아래에 전체코드를 적을 테니 참고하세요

import mysql from 'mysql';

var connection = mysql.createConnection({
  host: 'localhost',
  user: 'root',
  password: '1234',
  database: 'hotel_review',
});

connection.connect();

다음과 같이 connection이란 함수를 사용하여 우리가 가지고 있는 MySQL데이터와 연동을 시킬 수 있습니다. host와 user, password, database들은 사용자에 맞게 작성해주세요.

app.get('/api/hotel_name', (req, res) => {
  connection.query('SELECT * FROM hotel_name_list', (err, rows, fields) => {
    if (err) {
      console.log('데이터 가져오기 실패');
    } else {
      res.send(rows);
    }
  });
});

저는 API를 GET방식으로 사용할 것이라 app.get함수를 사용했습니다. Method마다 다른데 Post방식은 app.post를 사용합니다. 참고하세요. 다음 포스팅때 다룰 예정입니다.

req는 request, res는 response입니다.
get방식이라 request(요청)하는 것보다는 response(응답)을 쓰는게 맞겠죠?

query문은 가져올 테이블에 맞게 씁니다. SQL쿼리문으로 알맞게 작성해 주세요. 저는 필요한 rows들만으로 이루어진 테이블을 만들었기 때문에 모두 가져와도 되어서 *을 사용했습니다.

마지막으로 에러가 나지 않았을 때, res.send(rows)를 사용하여 API를 전송합니다.


해당 작업을 마쳤으면 서버를 켜고 쿼리가 잘 날려졌는지 Postman으로 작업확인해봅니다. postman으로 API확인하는 법은 최근에 알게 되었는데 정말 편합니다. ㅎㅎ 덕분에 REST API다루기가 참 용이해졌어요.

잘 응답해주는걸 볼 수 있습니다.
이제 React에서 해당 API를 fetch API를 사용해서 받아보도록 하겠습니다.
axios API를 사용할 예정이었는데 생각보다 선택하는 방법이 어려워서 fetch로 일단 했습니다. 코드 수정할 예정입니다.

React.js

일단 HotelName이라는 컴포넌트를 새로 만들었습니다. 컴포넌트 나누는건 중요하니깐요. 깔끔하고

API를 받는 함수를 작성합니다.

const fetchHotels = async() => {
  try {
    const response = await axios.get('http://localhost:3001/api/hotel_name');
    setTotalHotels(response.data);
    console.log('fetch HotelNames');
  } catch (e) {
    console.log("에러났습니다.", e);
  }
};

함수 이름은 명확할 수록 좋습니다. axios를 사용해 API를 받아 state에 저장했습니다.
받은 state로 적절하게 render 해주면 됩니다.

저는 긴 함수를 통해 나라별, 지역별 호텔이름을 선택할 수 있도록 만들었습니다.

전체코드는 다음과 같습니다.

// Hotels/HotelsName.js
import React, { useState, useEffect } from 'react';
import axios from 'axios';

function HotelsName() {
  const [totalHotels, setTotalHotels] = useState([]);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);

  const fetchHotels = async() => {
    try {
      // 요청 처음에 초기화
      setError(null);
      setTotalHotels([]);
      // loading 상태 true
      setLoading(true);

      const response = await axios.get('http://localhost:3001/api/hotel_name');
      setTotalHotels(response.data);
      console.log('fetch HotelNames');
    } catch (e) {
      setError(e);
    }
    setLoading(false);
  };
  
  useEffect(() => {
    fetchHotels();
  }, []);

  //Country
  const [selectedCountry, setSelectedCountry] = useState(null);
  const hotelsCountries = totalHotels.map(hotel => hotel.country);
  const selectCountry = (e) => {
    setSelectedCountry(e.target.value);
  }

  //Location
  const [selectedLocation, setSelectedLocation] = useState(null);
  const hotelsLocations = totalHotels
    .filter(hotels => selectedCountry === hotels.country)
    .map(hotel => hotel.location);
  const selectLocation = (e) => {
    setSelectedLocation(e.target.value);
  }

  //Name
  const hotelsNames = totalHotels
    .filter(hotels => selectedLocation === hotels.location)
    .map(hotel => hotel.hotel_name);
  

  if (loading) return (<div className='loading'><h1>로딩중..</h1></div>);
  if (error) return (
    <div className='error'>
      <h1>로딩중 에러가 발생했습니다.</h1>
      <button onClick={fetchHotels}>다시 불러오기</button>
    </div>);
  if (!totalHotels) return null;
  
  return (
    <div>
        <label>나라: </label>
        <select id="country-select" defaultValue="default" onClick={selectCountry}>
          <option value="default" disabled>
            Choose a Country ...
          </option>
          {[...new Set(hotelsCountries)].map((hotelsCountry, key) => (
            <option value={hotelsCountry} key={key}>{hotelsCountry}</option>
          ))}
        </select>
        <br></br>

        <label>지역: </label>
        <select id="location-select" defaultValue="default" onClick={selectLocation}>
          <option value="default" disabled>
            Choose a Location ...
          </option>
          {[...new Set(hotelsLocations)].map((hotelsLocation, key) => (
            <option value={hotelsLocation} key={key}>{hotelsLocation}</option>
          ))}
        </select>
        <br></br>
        
        <label>호텔 이름: </label>
        <select id="hotels-select" defaultValue="default">
          <option value="default" disabled>
            Choose a Hotel ...
          </option>
          {hotelsNames.map((hotelsName, key) => (
            <option value={hotelsName} key={key}>{hotelsName}</option>
          ))}
        </select>
      </div>
  );
}

export default HotelsName;

깔끔하게 설명하고 싶은데 깔끔한 코드가 아니라 못하겠네요...ㅜㅜ 코드 지적 달갑게 받겠습니다!

중간에 Country와 Location은 중복된 것들을 제거하고자 [...new Set()]을 사용했고요, map함수로 배열로 나타내어 render시켰습니다.

어찌저찌 MySQL과 Express를 연동시켜 호텔이름들을 선택할 수 있게 구성했습니다.
이제 호텔이름을 선택한 것을 검색하면 알맞는 리뷰를 화면에 뿌릴 수 있게끔 해줘야겠죠?

다음 포스팅에서 POST방식을 사용하여 알맞게 검색기능을 완성해봅시다!


이전 포스팅: csv파일을 MySQL에서 불러오기
다음 포스팅: Express에서 DB(MySQL)데이터 불러와 화면에 입력하기

profile
프론트엔드 개발 공부 시작합니다~ 같이 공부해요!

0개의 댓글