zeroCho[1/8] 끝말잇기 - useState, class component vs function component, webpack, module, build

목차
강의 소스: https://github.com/zerocho/react-webgame
[0/8] 구구단 - state, JSX, babel, Fragment, setState, ref
[1/8] 끝말잇기 - useState, class component vs function component, webpack, module, build
[1/8] 끝말잇기 - useState, class component vs function component, webpack, module, build
[2/8] 숫자야구. 3-1. import와 require 비교
[2/8] 숫자야구 - map, key, 컴포넌트분리, props, 메서드바인딩(this), 동작원리, 구조분해, 이벤트
[3/8] 반응속도체크 - createRoot, useEffect, useRef, 조건문, return 내부 for과 if 쓰기
[4/8] Rock Scissors Paper - LifeCycle, closure, 비동기함수, 고차함수, useEffect를 이용한 lifeCycle,
[5/8] Lotto - componentDidUpdate, useEffect, useMemo, useCallback
[6/8] 틱택토 - const [state, dispatch] = useReducer(reducer, initialState), action
깃 링크: https://github.com/Harimad/zeroReact/commit/95d58a0058641d321d113261a2b24f12f184d7cd
Class 에서는 state를 객체 하나로 데이터를 묶었다.
Hooks 에서는 state를 useState를 써서 분리한다.
Hooks에서 input의 ref를 쓸때는 useRef를 써서 DOM에 접근한다.
// 함수 컴포넌트 + setState, ref => Hooks
const GuGuDan = () => {
const [first, setFirst] = React.useState(Math.ceil(Math.random() * 9));
const [second, setSecond] = React.useState(Math.ceil(Math.random() * 9));
const [value, setValue] = React.useState('');
const [result, setResult] = React.useState('');
const inputRef = React.useRef(null);
const onChangeInput = (e) => {
setValue(e.target.value);
};
const onSubmitForm = (e) => {
e.preventDefault();
if (parseInt(value) === first * second) {
setResult(`정답: ${value}`);
setFirst(Math.ceil(Math.random() * 9));
setSecond(Math.ceil(Math.random() * 9));
setValue('');
inputRef.current.focus();
} else {
setResult('땡');
setValue('');
inputRef.current.focus();
}
};
return (
<React.Fragment>
<div>{first} 곱하기 {second}는?</div>
<form onSubmit={onSubmitForm}>
<input ref={inputRef} onChange={onChangeInput} value={value} />
<button>입력~~</button>
</form>
<div id="result">{result}</div>
</React.Fragment>
);
};
2-2. Class와 Hooks 비교하기
1. Re-rendering 차이점
Classstate가 바뀔때마다 render() 함수만 re-rendering 된다.
Hooksstate가 바뀔때마다 component 전체가 re-rendering 된다 (약간 느릴 수 있다)
2. 속성 사용: class -> className, for -> htmlFor
Q. hooks 부분에서 state를 객체형으로 하나로 만들면 어떨까?
const [state, setState] = React.useState({
first: ~~~,
second: ~~~,
value: '', result: '',
});
->this.setState와는 다르게 일일이 setState를 쓸때마다 데이터를 바꿔줘야 작동한다.(불편)
Q. 옛날state를 쓰는 경우 setState는 콜백함수를 호출하는 방식으로 쓴다.
setResult((prevResult) => {
return ~~~~
});
Q. onSubmitForm 함수가 호출될때 state 변경이 4군데 인데 rerendering이 4번 일어날까?
->그렇지 않다.
useState의 값 변경은 비동기 이기 때문에
state 4군데의 변경을 자동으로 하나의 rendering으로 바꿔준다.
Q. hooks 렌더링 새로고침
class 같은경우엔 render함수만 리렌더링 되고
함수형으로 사용할때에는 전체가 리렌더링이 된다고 하셨는데
그걸방지하는 hooks가 usecallback을 사용해서 막는건가요?
-> 함수는 useCallback으로, 값은 useMemo로 캐싱해둡니다
2-3. 웹팩 설치하기
CRA를 쓰면 편하긴 하지만 동작방식을 이해하기 어렵기 때문에 유연한 사용이 불가능하다.
그러므로 아래의 웹팩설치 방식을 수동으로 할줄 알아야한다.
1. npm init
설명: package.json 파일 생성
기능: react package를 관리한다.
2. npm i react react-dom
설명: react와 react-dom을 설치한다.
3. npm i -D webpack webpack-cli
설명:
-D는 Development로 개발용도 라는걸 말한다.
webpack과 webpack-cli를 설치한다.
4. webpack.config.js 파일 생성
설명: modue.exports = {} 에 채워넣을 예정
5. client.jsx 파일생성
const React = require('react')
const ReactDom = require('react-dom')
ReactDom.render() 입력
6. index.html 생성
js 파일 연결
2-4. 모듈 시스템과 웹팩 설정
깃 링크: https://github.com/Harimad/zeroReact/commit/caff0f1f5d92bf8d80bb7f6f1b3bbb23e5fb3546
-> 구조분해할당문법. destructuring.
const Component = React.Component와 같은 뜻이다.
//WordRelay.jsx 파일
const React = require('react')
const { Component } = React
class WordRelay extends Component {
state = {}
render() {}
}
module.exports = WordRelay
Q. Directory 구조?

client.jsx가 따로따로 분리해놓은 컴포넌트들을 담아주는 진입점(entry)같은 개념이고
webpack이 client.jsx 파일 및 다른 컴포넌트 파일들을 하나로 묶어준 다음 app.js라는 파일에 담아준다
Q. create-react-app 에서는 import와 export default를 쓰던데, 무슨 차이인가요??
create-react-app도 내부적으로 webpack설정을 하고있다면 똑같아야하는거아닌가요?
-> create-react-app에서는 웹팩 설정을 import랑 export를 쓰도록 설정해놓았겠죠?
웹팩설정을 바꾸면 create-react-app과 똑같이사용이가능합니다.
Q. const React = require("react"); 대신에 import React from "react"; 로 사용해도 될까요?
-> 되는데 웹팩 설정 하셔야 합니다.
2-5. 웹팩으로 빌드하기
깃링크:https://github.com/Harimad/zeroReact/commit/f449cc72dc648a44b6d2ecfe8520d62d748d251e
CLI에 webpack이 안되면 해결할 3가지 방법
1. 명령어 등록
2. package.json 스크립트에 적어주기
"scripts": {
"dev": "webpack"
}
-> npm run dev 실행
3. npx webpack 로 실행
webpack을 해도 babel이 깔려있지 않아서 문법 오류가 발생한다.
npm i -D @babel/core 기본적인 babel, 최신문법 바꿔줌
npm i -D @babel/preset-env 나의 브라우저 환경에 맞춰줌
npm i -D @babel/preset-react jsx 바꿔주는것
npm i -D babel-loader 바벨과 webpack을 연결
webpack.config.js에
modules를 적용한다.
2-6. 구구단 웹팩으로 빌드하기
혼자 해본 깃 링크: https://github.com/Harimad/zeroReact/commit/6e00ee33901220cbb54039b32eeac5d6b8ee871e
깃 링크: https://github.com/Harimad/zeroReact/commit/6fa51e4bd2bc2682f7fc07c7c2b66586136bdd4b
강의 북마크
3:33 - webpack.config.js 파일에서 devtool을 개발중에는 'eval'을 쓰고 배포할때는 'hidden-source-map'으로 바꾼다.
5:36 - webpack.config.js 파일에서 module 의 rules 부분에서 test 값의 정규표현식을 /\.jsx?$/ 처럼 $를 추가한다.
7:03 - package.json 파일에서 script 부분에서 "dev": "webpack"만 남긴다.
7:25 - zeroCho는 webpack.config.js 파일에서 entry를 웬만하면 client 파일로 맞춘다.
9:43 - GuGuDan 컴포넌트 파일에서 const { useState, useRef } = React를 추가한다.
10:00 - GuGuDan 컴포넌트 에서 return 부분에 있는 <React.Fragment></React.Fragment>를 <></>로 바꿔도 된다.
10:25 - 구구단 관련 파일을 다 만들었으면 Cli 에서 npm run dev or npx webpack 을 입력한다. -> html파일을 켜본다!
2-7. @babel/preset-env와 plugins
깃 링크: https://github.com/Harimad/zeroReact/commit/fe4dab8dc6e0076c4e89e0194cd940b5e9ab5093
깃 보완 링크: https://github.com/Harimad/zeroReact/commit/d1f1992a286027a58a3fefd960791f87cafeffbc
preset은 plugin들이 수십개 모인 것이다. 그래서 설정할게 많다.
// webpack.config.js 파일
module: {
rules: [
{
test: /\.jsx?$/,
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env', '@babel/preset-react'], //얘가
plugins: [], //얘의 모음집이다.
},
},
],
},
기본형은 위와 같다. 하지만 preset은 plugin들의 모음이기 때문에 preset에서도 따로 설정이 가능하다.
그래서 따로 설정하려면 preset의 요소 각각을 배열로 만들고 인자를 따로 넣어줘야한다.
browser 세팅을 custom할 수 있다. (웹팩이 브라우저 대응까지 해줌)

Browerslist 링크: https://github.com/browserslist/browserslist#readme
GitHub - browserslist/browserslist: 🦔 Share target browsers between different front-end tools, like Autoprefixer, Stylelint a
🦔 Share target browsers between different front-end tools, like Autoprefixer, Stylelint and babel-preset-env - GitHub - browserslist/browserslist: 🦔 Share target browsers between different front-en...
github.com
webpack의 5가지 컨셉만 이해하고 있으면 webpack의 기본 개념은 이해했다고 볼 수 있다.

webpack Link: https://webpack.kr/concepts/
Concepts | 웹팩
웹팩은 모듈 번들러입니다. 주요 목적은 브라우저에서 사용할 수 있도록 JavaScript 파일을 번들로 묶는 것이지만, 리소스나 애셋을 변환하고 번들링 또는 패키징할 수도 있습니다.
webpack.kr
실행 화면

Q. npm run build 하는거랑 webpack하는거랑 차이가 뭔가요?
-> npm run build는 단순히 package.json에 적혀있는 build 스크립트를 실행할 뿐입니다
느낀점:
jsx가 바벨에 의존적이구나..
그리고 create- react app 에서 빌드는 웹팩으로 되는것이고..
처음에 create react app으로 리액트를 접해서 이해 안됬던게 이해된다.
2-8. 끝말잇기 Class 만들기
깃 링크: https://github.com/Harimad/zeroReact/commit/b74eb2360ed4187dc15de664e5a983589c61bce2
끝말잇기 코드 넣는건 깃 링크보고 간단하게 확인할것. 어려운건 없다.
Q. path.join() vs path.resolve() ?
path.resolve('a', '/', 'bc) // 결과: /bc
path.join('a', '/', 'bc) // 결과: ./a/bc
resolve는 /를 절대경로(루트폴더)로 인식하고, join은 무시합니다.
2-9. 웹팩 데브 서버와 핫 리로딩
깃 링크: https://github.com/Harimad/zeroReact/commit/8aebdbfef3e449b3ca5bab54a59b16b0edb97c0f
강의 흐름
1. 리액트 이전에 있는 핫 로더랑 같은 react-refresh 다운로드
npm i -D react-refresh @pmmmwh/react-refresh-webpack-plugin
2. 개발용 서버 다운로드
npm i -D webpack-dev-server
Q. webpack-dev-server 기능
webpack.config.js 파일속
devServer > devMiddleware 프로퍼티 안의 경로에 빌드 결과물들을 메모리로 저장한다.
devServer > static 프로퍼티는 index.html을 찾는 녀석이다. 이 녀석을 설정 해놓으면, index.html 파일을 실행하면 저장결과물을 여기다가 재공해준다.
Q. webpack-dev-server의 최종 기능?
소스코드가 수정되면 그걸 감지하고 저장했던 결과물을 수정해준다.
npm run dev로 파일을 빌드해서 localhost에 접속해서 확인해보면 코드 수정시에 리랜더링 되는 걸 알 수 있다.
3. package.json 에서 script 객체의 dev에
webpack-dev-server --hot였던걸
webpack serve --env development 로 바꿔줌.(최신버전)
4. webpack.config.js에서 방금 다운받은 pmmm을 가져옴
5. plugins 안에 new RefreshWebpackPlugin()를 넣어줌 -> 앞으로 build할때마다 plugins안에 앞의 코드가 실행됨
6. module > rules > options > plugins 안에 'react-refresh/babel' 추가
즉, rules안에 있는 로더인 'babel-loader'의 플러그인을 넣는것이다.
기능: 바벨이 최신 문법 을 옛 JS 로 만들때 핫리로딩 기능을 추가시켜줌.
★5,6번을 안넣어 줘도 WordRelay.jsx 코드가 바뀌어도 리로딩은 해준다. 저장된 데이터는 날라간다.
★그러나 5,6을 넣어주면 변경점만 바꿔주는 리랜더링을 해준다. 저장된 데이터가 날라가지 않는 이점이 생긴다.(중요)
7. module.exports 객체 안에 devServer 추가
안에 내용은 zeroCho Git내용을 기반으로 넣는다.
워낙 옛날 버전이 많아서 혼란이 올 수 있다. 다른 사람의 코드는 우선 무시하자.
8. 이제 결과물 확인 시간
npm run dev를 한다.
그럼 package.json의 scripts > dev에 적은 대로 'webpack serve --env development'가 실행됨. 즉, 빌드 결과물을 돌림
빌드가 완료되면서 http://localhost:8080/ 접속이 가능함.
접속해보면 잘 빌드된걸 확인 할 수 있다.
WordRelay.jsx에서 값이 변경되면 화면이 rerendering됨
2-10. 끝말잇기 Hooks로 전환하기
깃 링크: https://github.com/Harimad/zeroReact/commit/5fe4a6cc8d34b3a55f232e2a384d5f6ced47a9da
Class -> Hooks 로 전환하는 시간임. 쉬움.
1. state부분은 useState로 하나씩 설정해줌.
2. input의 ref 속성은 useRef를 써줌.
const { useRef } = require('react') //useRef 불러오기
const inputRef = useRef(null) //useRef 설정
<input ref={inputRef} value={value} onChange={onChangeInput}/> //useRef 설정 적용
3. 함수는 return 밖에서 정의함
4. render() 메서드를 return () 로 바꿔줌