[웹 게임을 만들며 배우는 React] 끝말잇기(hooks, 웹팩, 데브서버와 핫 리로딩)

안지수·2023년 3월 14일
0

😊 hooks 개념과 특징

  • hooks: class component의 단점을 극복하며 리액트의 여러 기능들을 사용할 수 있게 한 라이브러리 (함수 컴포넌트에서만 사용 가능) -> setState를 대체했다고 할 수 있음!
  • class component의 문제점: 문법 어렵, 축소 어렵, 최신 기술들이 효과적으로 적용되지 않음

ex> state hook: useState, effect hook: useEffect
1. useState: 가변적인 상태를 지니고 있을 수 있게 해줌/ 파라미터: 기본값
2. useEffect: 컴포넌트 렌더링될 때마다, 특정 작업 수행하도록

--> hooks 사용 시에는, render() 도 안써도 됨!

😊 class component와 hooks 차이

-> hooks 쓰면 코드 짧아짐 but 렌더링 시, 코드 통째로 다시 실행되어서, 조금 느릴 수 있음
-> 리액트에서는 class랑 for 속성 못 씀

-> 이렇게 써줘야 함
-> hooks 쓸 때는 state를 나눠서 써야 함

😊 webpack 개념과 설치

  • 모듈 번들러: 여러 개의 나누어져 있는 파일을 하나의 파일로 묶어서, 한 번의 요청을 통해 가져올 수 있게 하는 라이브러리 (그 중 하나가 webpack): 보통 js나 json 파일만 이해
    -> 자바스크립트가 아닌 파일도 이해하기 위해(html, css,,,) (웹 팩의 'loader'를 이용하여)
    -> 합치면서, 바벨도 적용할 수 있고, 필요없는 코드도 제거할 수 있다.
    -> 웹 팩 실행을 위해 노드(자바스크립트 실행기) 필요
    ----> 웹 팩 실행을 위해, 노드와 npm 필요! 이를 통해서 리액트와 바벨 불러올 수 있으므로 따로 설정하지 않아도 됨

<웹 팩 개발 환경 설정하기>
1. npm init -> package.json 파일 만들어짐
2. npm install react react-dom -> 리액트 설치
3. npm i babel-loader: babel과 webpack을 연결
npm i @babel/core: 바벨의 기본적인것
npm i -D @babel/preset-env: 브라우저에 맞게 최신문법도 옛날 문법을 지원(ES6을 ES5로)
npm i -D @babel/preset-react : JSX를 인식
-> 바벨 설치
4. npm i -D webpack webpack-cli -> 웹팩 설치
*'-D' 옵션: 배포할때 말고 개발할때만 쓰겠다는 의미 (웹 팩도 개발할 때만 필요)
5. client.jxs 파일

-> 클라이언트 파일에 class를 생성할 경우에는, class가 많아질 경우 유지보수가 어려워진다. 따라서, wordRealy.jsx 파일을 따로 만들어준다.

-> 따로 분리하는 경우에는 client 파일에 다음과 같이 'const WordRelay = require('./WordRelay');' 코드를 추가해주었다.
6. wordRelay.jsx 파일

-> 따로 분리해준 wordRelay 파일에서도 react를 불러와줘야 한다. 그리고, 다른 파일에서 이 파일을 불러올 수 있도록, 'module.exports = WordRelay;' 추가/ 클래스 부분의 경우 class WordRelay extends React.Component라고 써주어야하지만 'const { Component } = React;' 를 작성해 줌으로서 class WordRelay extends Component로 줄일수 있음

  1. webpack.config.js 파일

    -> module.exports안에 몇가지 설정을 해주어야 함
    -> entry입력, output출력 (입력을 모듈을 적용해서 출력을 하겠다는 의미)
    🧨entry(입력-client.jsx, wordRealy.jsx)와 output(출력-app.js)이 중요
    'mode: 'development'' 는 실서비스를 할때는 production으로 변경해줌.
    'devtool: 'eval'' 는 빠르게 하겠다는 의미
    resolve: {
    extensions: ['.js', '.jsx']
    },

    의 경우는 entry 안에 'app: ['./client']'에서 client뒤에 확장자 명을 생략해주기 위해서 작성해주는 것입니다.
    -> 또한 entry안에서 client.jsx가 WordRelay.jsx를 불러 오고 있기 때문에 WordRelay.jsx는 작성하지 않아도 됨
    -> path: dist의 실제 경로는 C:... 이지만 path.join를 사용함으로서 현재 폴더의 dist폴더를 말합니다.

  2. webpack 명령어 등록 (package.json 파일)

    -> 'npm run dev' or 'npx webpack' 명령어를 통해 웹팩 실행 가능
    -> dist 폴더 안에 'app.js' 파일 생성!

😊 webpack 데브서버와 hot 리로딩

webpack-dev-server를 통한 핫 리로딩: 소스 코드 수정 시, 직접 빌드하지 않고, 웹팩이 실시간으로 빌드해줌 (웹 팩의 기능 중 하나임!) -> 변경점이 있는 경우, 새로고침 시 바로 반영(리로딩)
!! 핫 리로딩: 새로고침 없이, 데이터가 그대로 유지되게끔
*핫 리로딩과 리로딩의 차이: 핫 리로딩기존 데이터 유지하면서, 화면 바꿔줌/ 그냥 리로딩: 기존 데이터 사라지면서 새로고침

*다음의 2가지를 설치한다.
1. npm i react-refresh @pmmmwh/react-refresh-webpack-plugin -D
2. npm i -D webpack-dev-server
3. package.json 파일

-> 기존 package.json 파일에서, webpack 부분을 아래와 같이 수정한다.
4. webpack.config.js 파일
-> 위에서 받은 plugin들을 webpack에 적용

const path = require('path');
const RefreshWebpackPlugins = require('@pmmmwh/react-refresh-webpack-plugin');


module.exports = {
    name: 'word-relay-setting',
    mode: 'development', //실서비스 : production
    devtool: 'eval',
    resolve: {
        extensions: ['.js', '.jsx']
    },
    
    entry: {
        app: ['./client'],
    }, // 입력

    module: {
        rules: [{
            test: /\.jsx?/,
            loader: 'babel-loader',
            options: {
                presets: [
                    ['@babel/preset-env', {
                    targets: {
                        browsers: ['> 1% in KR'],
                    },
                    debug: true,
                }],
                 '@babel/preset-react',
                ],
                plugins: [
                    '@babel/plugin-proposal-class-properties',
                    'react-refresh/babel',
                ]
            }
        }],
    },
    plugins:[
        new RefreshWebpackPlugins()
    ],

    output: {
        path: path.join(__dirname, 'dist'), //A:\Documents\Github...
        filename: 'app.js',
        publicPath: '/dist/',
    }, // 출력
    devServer: {
        publicPath: '/dist/',
        hot: true,
    },
};

-> 플러그인에 react-refresh/babel을 넣어서 바벨이 작동할 때 핫리로딩 기능까지 실행하도록
5. npm run dev 명령어 입력 후, 로컬호스트:8080으로 접속: 결과가 publiPath에 저장됨

😊 구구단 webpack으로 빌드하기

-> 위의 웹 팩 개발 환경과 설정과 똑같아
1. 터미널에서 cd 구구단 파일로 이동
2. npm init
3. npm i react react-dom (리액트 설치)
4. npm i -D webpack webpack-cli (웹 팩 설치)
5. npm i babel-loader @babel/core
npm i -D @babel/preset-env
npm i -D @babel/preset-react (바벨 설치)
6. client.jsx 파일에서 구구단 파일 불러오기
7. package.json 수정해주기 (webpack)
8. client.jsx
9. gu gu dan.jsx로 옮기기 (리액트 불러오고) -> 클래스 컴포넌트로 해도 되고, hooks로 해도 됨 (class component 코드에서, hooks로 바꾸는 것도 연습하기)
10. 파일 쪼갰으면, 구구단.jsx 마지막에 module.exports = GuGuDan
11. webpack.config.js 파일 생성하여 작성 (플러그인,,,등을 작성)
12. npx webpack (npm run dev) - app,js 생성
13. 빌드: lecture 파일에서 npm run dev

😊 끝말잇기 class component 버젼

const React = require('react');
const { Component } = React;

class WordRelay extends Component {
  state = {
    word: '제로초',
    value: '',
    result: '',
  };

  onSubmitForm = (e) => {
    e.preventDefault();
    if (this.state.word[this.state.word.length - 1] === this.state.value[0]) {
      this.setState({
        result: '딩동댕',
        word: this.state.value,
        value: '',
      });
      this.input.focus();
    } else {
      this.setState({
        result: '땡',
        value: '',
      });
      this.input.focus();
    }
  };

  onChangeInput = (e) => {
    this.setState({ value: e.target.value });
  };

  input; // this.input을 생성

  onRefInput = (c) => {
    this.input = c;
  };

  render() {
    return (
      <>
        <div>{this.state.word}</div>
        <form onSubmit={this.onSubmitForm}>
          <input ref={this.onRefInput} value={this.state.value} onChange={this.onChangeInput} />
          <button>클릭!!!</button>
        </form>
        <div>{this.state.result}</div>
      </>
    );
  }
}

module.exports = WordRelay;

😊 끝말잇기 hooks로 전환하기

const React = require('react');
const { useState, useRef } = React;

const WordRelay = () => {
  const [word, setWord] = useState('제로초');
  const [result, setResult] = useState(' ');
  const inputRef = useRef(null);

  const onSubmitForm = (e) => {
    e.preventDefault();
    console.dir(e.target.children.word.value);
    if (word[word.length - 1] === e.target.children.word.value[0]) {
      setResult('딩동댕');
      setWord(e.target.children.word.value);
      e.target.children.word.value = '',
      inputEl.current.focus()
    } else {
      setResult('땡');
      e.target.children.word.value = '',
      inputEl.current.focus();
      };
    }
  };

  const onChangeInput = (e) => {
    setValue(e.target.value);
  }; 

  return (
    <>
      <div>{word}</div>
      <form onSubmit={onSubmitForm}>
        <label id="label" htmlFor="wordInput">글자를 입력하세요.</label>
        <input
          defaultValue="제로초"
          id="word"
          ref ={inputEl}
        />
        <button>클릭!!!</button>
      </form>
      <div>{result}</div>
    </>
  );



module.exports = WordRelay;

😊 controlled input과 uncontrolled input

: form을 다루는 2가지 방법

  • controlled input: value, onChange 존재하는 것/ 복잡한 경우에는 이게 좋음/ 사용자가 값을 입력할 때마다 onChange 이벤트가 발생하여, 항상 최신의 값으로 유지 됨!!
  • uncontrolled input: 그 2개가 없는 것/ value가 onSubmit에서만 쓰이는 경우- value를 대체 가능!! ref통해 접근 가능/ button을 클릭해야 비로소 정보를 가져올 수 있다.
    -> 리액트에서는 컨트롤드 인풋을 더 권장 (언컨트롤드가 더 간단)
    ---> value가 onSubmit에서만 쓰이면, 지우고 언컨트롤드 인풋으로 전환할 수 있다. 컨트롤드 인풋에서는 setState로 가능! 언컨트롤드 인풋은 진짜 간단한 경우에!! onSubmit에서 그거만 꺼내오는 경우.
    --> 실시간으로 값이 필요할 때는 제어(Controlled ipnut)를 사용하고,
    --> 불필요한 재렌더링을 줄이고 제출 시에만 값이 필요할 때는 비제어 (UnControlled input)


*언컨트롤드 인풋에서 초기값 지정을 위해서는: default value

⭕ 나의 언어로 정리

: class 컴포넌트는 유지보수가 어렵다는 등 여러 한계점이 존재한다. 따라서, 함수 컴포넌트가 더 편리하다. 함수 컴포넌트에서, class 컴포넌트의 기능들(setState)을 쓸 수 있게 한 것이 hooks이다. use~~로 시작하는 것들이 hooks임. render도 안써도 되고 해서, 되게 코드가 간단해진다.
자바스크립트는 모듈을 지원하지 않는다. 즉, 하나의 html 파일에서는 하나의 파일만을 불러올 수 있다는 것이다. 하지만..컴포넌트가 여러 개일 경우에는 분리해서 작성하므로 여러 개의 파일을 불러와야할 경우가 있다. 여러 개의 파일을 가져와서 하나의 파일로 합쳐주기 위한 것이 바로 '웹팩'이다. 웹팩은 자바스크립트 파일, json파일 만을 이해하는데, html, css와 같은 파일들도 이해하기 위한 것이 loader이다. 웹팩은 노드를(자바스크립트 실행기)를 이용하여 해석이 되어진다. 따라서, 바벨과 리액트도 노드의 도구인 npm을 이용하여 설치할 수 있다. webpack 결과는 입력값을 특정 모듈을 적용해 출력을 내보낸다. 결과는 app.js 파일에 쓰여진다.
하지만 코드를 수정할 때마다, 빌드를 다시 해야하므로 너무 번거롭다. 웹 팩은 이러한 점을 보완하기 위한 기능을 제공하다. 데브서버를 통한 핫 리로딩 기능이다. 즉, 웹 팩의 데브서버를 통해 실시간으로 빌드를 해주는 것이다. 그냥 리로딩과 핫리로딩의 차이점은 리로딩은 새로고침 시, 초기화 된다는 것 핫 리로딩은 기존은 데이터를 유지 시켜준다는 것이다!!! 또 form을 관리해주는 2가지의 방법이 있는데, 실시간으로 렌더링해서 최신값으로 유지시켜 주는 것은 컨트롤드 인풋, ref 통해 접근하고, 버튼을 눌렀을 때 비로소 값을 얻을 수 있는 것은 언컨트롤드 인풋이다.
---> 어쨌튼, hooks는 함수 컴포넌트에서 class component를 쓰기 위한 라이브러리 인거고,,, 웹 팩은 여러 파일을 하나의 파일로 합치기 위한 것이고, 여러 기능들(핫 리로딩, 바벨과 리액트 불러옴)을 제공한다는 것.

--> 즉, 원래 html 파일에서 리액트 바벨 다 불러와서 하던 것을 client와 html파일을 분리하고.... client 파일이 길어질 것 같아서, client와 특정 jsx 파일들로 또 나눔. client에서 특정 jsx 파일 불러오게 하고... 여러 개의 파일들을 하나로 합치기 위해 웹 팩 사용

profile
지수의 취준, 개발일기

0개의 댓글