리액트 노드 프로젝트 소스 분석 / React.js, Node.js 사용법 정리

학교에서 선생님과 학생이 실시간으로 소통하는 수업 도구 프로젝트를 맡게 되어 분석해 보았습니다.
외주사에서 프론트는 리액트, 백엔드는 노드로 개발한 프로젝트입니다.


리액트 프로젝트 분석 (프론트)

리액트는 실행 시 자동 빌드되는 public 폴더의 index.html 파일에서 url에 따라 컴포넌트만 바뀌며 동작합니다.
index.js에서 ReactDom.render 시 첫 인자로 받은 컴포넌트(App.js)를 index.html의 <div id="root"></div> 안에 렌더링하며, 각 하위 컴포넌트는 부모 컴포넌트가 렌더링 되거나 this.props 또는 this.state가 변경될 때마다 리렌더링 됩니다.

/src/App.js 분석

import React from 'react';
import { Provider } from 'react-redux';
import { store, history } from './redux/store';
import PublicRoutes from './router';
import './style/styles.less';

const App = () => (
    <Provider store={store}>
        <PublicRoutes history={history} />
    </Provider>
);

export default App;

App.js가 리액트 메인 컴포넌트이며, 이 안에 리덕스 Provider 컴포넌트로 Store를 연동하고 Router를 지정해줄 수 있습니다.

현재 프로젝트에서는 선생님 화면 컴포넌트, 학생 화면 컴포넌트 각각 별도의 App.js, AppRouter.js를 갖고 있으며 메인 router.js의 div에서 URL Path 앞부분으로 라우팅하여 선생님 App.js, 학생 App.js 중 하나를 렌더 합니다.

선생님 App.js는 부모 컴포넌트에서 받은 props 또는 리덕스 connect 시 받은 스토어 state와 액션 함수를 this.props로 꺼내 쓸 수 있습니다. 이를 기반으로 render() 함수에서 컴포넌트 JSX를 만들고 return 하여 화면을 렌더링 합니다.

현재 프로젝트에서 선생님 App.js 렌더 시 그려주는 주요 컴포넌트는 아래와 같습니다.

Topbar 상단 파란색 헤더 영역입니다.
Sidebar 좌측 메뉴 영역이며, 다른 메뉴 이동 시 URL Path를 변경합니다.
TabMenu 상단 탭 영역이며, 다른 메뉴 이동 시 기존 state를 리덕스에 저장 후 URL Path를 변경합니다.
AppRouter Scrollbar 컴포넌트로 감싸져 있으며,
변경 URL Path에 따라 다른 컴포넌트를 렌더하는 주 콘텐츠 영역입니다.
PageTitle AppRouter로 렌더링하는 각 콘텐츠 js 상단에서 공통적으로 렌더하는 공통 컴포넌트입니다.
제목, 주 기능 버튼 등이 있고 버튼 유무 변수, 버튼 클릭 이벤트 함수를 props로 받아서 사용합니다.

리액트 라이브러리 설치 명령어

npm install

현재 위치한 경로 package.json의 dependencies 기준으로 node_modules 폴더를 생성하고 라이브러리를 설치합니다.
node_modules 폴더는 용량이 커서 git으로 관리하지 않는 것이 좋습니다.

npm 명령어 사용 방법
https://0songha0.github.io/web-dev/2023-03-17-1
윈도우에 nvm 설치 후 nvm 명령어를 이용해 node 설치하고 IntelliJ를 재시작하면 Terminal에서 사용할 수 있습니다.

리액트 실행 명령어

npm run start

현재 위치한 경로 package.json의 scripts에 명시되어 있는 기본 start 명령어입니다.
커스텀 start.js를 실행하는 다른 명령어를 추가해줄 수도 있으며, 실행 종료 단축키는 Ctrl + C입니다.

리액트 렌더링 시 에러메세지

adjacent JSX elements must be wrapped in an enclosing tag. Did you want a JSX fragment <>...</>?

리액트 컴포넌트 렌더링 시 루트 태그가 2개 이상이면 발생하는 오류이며, Fragment로 감싸주면 해결됩니다.

리액트 Fragment

<Fragment></Fragment>

의미 없는 div 추가 없이 여러 자식을 그룹화하기 위해 사용하며, <></>으로 단축하여 사용할 수 있습니다.


리액트 클래스형 컴포넌트 생명주기 및 사용법

https://0songha0.github.io/web-dev/2023-05-27-1


리액트 함수형 컴포넌트

https://0songha0.github.io/web-dev/2023-05-28-1


리액트 URL 변경 방법

URL 이동하며 파라미터 넘겨주는 방법

this.props.history.push({
  pathname: "/이동할URL",
  state: { 파라미터1: '데이터' }
});

이동한 URL의 컴포넌트에서 파라미터 받는 방법

const 변수명 = this.props.history.location.state;

리액트 리덕스 사용법

https://0songha0.github.io/web-dev/2023-05-29-1


리액트 Storybook

리액트 스토리북을 이용하면 비즈니스 로직과 분리된 공통 UI 컴포넌트를 만들 수 있습니다.

스토리북 단점

스토리북의 컴포넌트 jsx를 수정하면 스토리북 빌드하고 나온 index.js를 프로젝트에 반영해야 적용되어 번거롭습니다.
컴포넌트가 많아져서 스토리북 빌드 파일 크기가 크면 git push 시 시간이 오래 소요되거나 실패할 수 있습니다.


노드 프로젝트 분석 (백엔드)

현재 노드 프로젝트는 Express 프레임워크로 개발되었습니다.

노드 Express 라우팅 방법

var express = require('express');
var router = express.Router();

router.use('/URL명1', (req, res) => {
    // 모든 HTTP 메서드에 대한 백엔드 처리
    res.send('응답');
});

router.get('/URL명2', (req, res) => {
    // get 메서드에 대한 백엔드 처리
    res.send('응답');
});

router.post('/URL명3', (req, res) => {
    // post 메서드에 대한 백엔드 처리
    res.send('응답');
});

module.exports = router;

위와 같이, 클라이언트에서 한 요청을 URL 분기하여 받고 백엔드 처리 후 데이터를 전달할 수 있습니다.


Websocket, MQTT

현재 프로젝트에서는 MQTT를 이용해 웹소켓 통신으로 데이터를 실시간 공유하고 있습니다.

MQTT 프로토콜 개념

mqttClient에서 메시지 브로커에 connect 후 토픽에 메시지를 Publish(발행)하여 보내거나 Subscribe(구독)하여 받습니다.
메시지 브로커는 토픽을 구독하는 클라이언트에 메시지를 전달해주는 역할을 합니다.

Topic (토픽)

토픽은 선생님 토픽, 학생 토픽으로 구분되어 있다. 선생님 토픽 예시는 아래와 같습니다.

pub/수업구분/${this.get수업코드()}/teacher/${this.get유저ID()}

MQTT 활용 프로세스 분석

  1. 프론트 App.js의 생성자에서 mqtt.connect 시 mqttUrl(mqttProtocol://백엔드IP:mqttProt), mqttOption을 넘깁니다.
  2. mqtt.conntect 시 반환되는 mqttClient를 이용해 .on(‘connect’, () => { }) 안에서 .subscribe 함수로 토픽을 구독해둡니다.
  3. mqttClient.on(‘message’, 함수명)으로 message 발생 이후 실행할 콜백 함수를 지정해둡니다.
  4. 다른 토픽에 데이터 전달이 필요한 프론트 위치에서 mqttClient.publish(토픽명, 메시지) 함수를 호출합니다.
  5. 백엔드 observer.js의 handleMqttMessage(토픽명, 메시지) 함수에서 받고, 토픽에 따라 다른 함수를 호출합니다.
  6. 백엔드 함수 내에서 node 내 객체 변경 처리 후, 동기화가 필요한 토픽에 publish하며 데이터를 보내줍니다.
  7. 콜백 함수로 지정했던 프론트 App.js의 handleMqttMessage(토픽명, 메시지) 함수에서 메시지에 따라 화면을 변경해줍니다.

리눅스 MQTT 실행 여부 확인

service mosquitto restart

active (running) 으로 되어있어야 정상적으로 실행되고 있는 것입니다.

리눅스 MQTT 재실행

sudo service mosquitto restart

웹 F12 보면 Websocket connection to ‘wss://도메인:포트’ falied:라면서 MQTT 연결이 안되고 offline mqtt 나오는 경우, 위 명령어로 재시작하면 정상 동작합니다.
sudo로 실행하지 않으면 Password를 요구하니까 sudo로 실행해야 합니다.


Canvas, Fabric

Fabric은 <canvas /> 위에 그려줄 도형, 선, 이미지 객체를 만들 수 있는 라이브러리입니다.

Canvas Json 변환 방법

JSON.stringify(canvas.toJSON());

Canvas의 fabric Object 객체 데이터를 Json으로 변환하여 보내면, 다른 Canvas에도 동일한 객체를 올릴 수 있습니다.

Canvas에 Json으로 변환된 객체 그려주는 방법

canvas.loadFromJSON(JSON.parse(jsonString), () => {
    canvas.renderAll();
    ctxStack = [canvas.toJSON()];
    canvasData = canvas.toJSON();
});

Leave a comment