들어가기

지금껏 Client 를 React 로 만들때 0부터 작성했었는데 이번엔 Bolierplate 인 create-react_app 을 사용해보려 한다

단순히 CRA만 사용해서 NodeJS와 같이 작업한다면, React 코드 수정시 매번 빌드를 다시 새로 해주어야 한다. 이러한 불편함을 막기위해 proxy를 설정하여 CRA를 클라이언트와 서버(Node) 사이에서 중간 다리 역할을 할 수 있게 해주자

[참고]
https://www.freecodecamp.org/news/how-to-make-create-react-app-work-with-a-node-backend-api-7c5c48acb1b0/
Thanks a lot !

환경 만들기

먼저 create-react-app 폴더 하나를 만들어주자

$ create-react-app node-cra-test

이제 node-cra-test 폴더 안에 client를 만들고 create-react-app 으로 생성된 모든 파일들을 옮겨주자

client 폴더 안과 밖에 yarn 이나 npm 을 따로 적용할 것이기 때문

client 폴더 밖의 root 경로에서 $ yarn init -y 커맨드를 입력해주면 바깥쪽에도 package.json 파일이 생성된다

방금 생성된 package.json에 아래의 코드를 넣어주자

...
"scripts": {
    "client": "cd client && yarn start",
    "server": "nodemon server.js",
    "dev": "concurrently --kill-others-on-fail \"yarn server\" \"yarn client\""
 },
"dependencies": {
    "body-parser": "^1.18.3",
    "express": "^4.16.4"
 },
"devDependencies": {
    "concurrently": "^4.0.1"
 }
  ...

concurrently : 커맨드를 동시에 실행하게 도와주는 모듈 패키지
--kill-others-on-fail : 커맨드 중 하나라도 에러가 발생하면 모두 종료시켜주는 옵션

위의 코드를 넣었으면 패키지를 설치할 수 있게 yarn install 을 입력하자

서버 생성

이제 Node 서버를 만들자

root 경로에 server.js 파일을 만들고 아래의 코드를 넣어보자

server.js

const express = require('express');
const bodyParser = require('body-parser');

const app = express();
const port = process.env.PORT || 5000;

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

// API 라우팅 !!!
app.get('/api/hello', (req, res) => {
  res.send({ express: 'Hello From Express' });
});

app.post('/api/world', (req, res) => {
  console.log(req.body);
  res.send(
    `I received your POST request. This is what you sent me: ${req.body.post}`,
  );
});

app.listen(port, () => console.log(`Listening on port ${port}`));

express 에 대해선 따로 설명 하지 않는다 - 참조

proxy

이제 제일 중요한 클라이언트(CRA)에서 서버로 요청하는 법이다

client/package.json

{
 ...
 "proxy": "http://localhost:5000/"
}

proxy는 URL을 대체해준다. CRA로 http://localhost:3000 으로 실행시켜도 위처럼 설정 되어있다면,
'/api/greeting' 으로 요청했을 때http://localhost:5000/api/greeting 으로 요청된다

테스트

이제 테스트를 해보자

client/src/App.js

import React, { Component } from 'react';

import logo from './logo.svg';

import './App.css';

class App extends Component {
  state = {
    response: '',
    post: '',
    responseToPost: '',
  };

  componentDidMount() {
    this.callApi()
      .then(res => this.setState({ response: res.express }))
      .catch(err => console.log(err));
  }

  callApi = async () => {
    const response = await fetch('/api/hello');
    const body = await response.json();
    if (response.status !== 200) throw Error(body.message);

    return body;
  };

  handleSubmit = async e => {
    e.preventDefault();
    const response = await fetch('/api/world', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ post: this.state.post }),
    });
    const body = await response.text();

    this.setState({ responseToPost: body });
  };

render() {
    return (
      <div className="App">
        <p>{this.state.response}</p>
        <form onSubmit={this.handleSubmit}>
          <p>
            <strong>Post to Server:</strong>
          </p>
          <input
            type="text"
            value={this.state.post}
            onChange={e => this.setState({ post: e.target.value })}
          />
          <button type="submit">Submit</button>
        </form>
        <p>{this.state.responseToPost}</p>
      </div>
    );
  }
}

export default App;

이런 React 코드를 넣고 실행해보자

$ yarn dev

테스트는 긴 설명이 없다. 그냥 직접 해보고 해석하자!