webpack을 사용하는 이유

여러 컴포넌트를 모아서 한방에 합쳐서 하나의 js파일로 만들어 준다.

합치면서 babel도 적용할 수 있고, console.log 같은 것도 모두 빼버릴 수 있는 기능을 제공한다.

 

webpack을 하려면 node를 알아야한다.

node는 js 실행기 그 이상 그 이하도 아니다. (백엔드 아님..)

react할 때 node를 알아야 한다. 라는것이 서버 백엔드를 알아야 한다는 것이 아니라는 것이다. webpack을 돌리기 위한 그 js실행기를 알아야 한다는 뜻이다.

 

1. node를 설치하고 

2. (터미널로 강의 폴더로 이동 후) npm init

3. package.json이 생성된다.

4. npm i react react-dom

5. npm i -D webpack webpack-cli 

   (-D는 개발용으로만 사용한다는 의미이다. 실제 서비스 할 때는 webpack이 필요 없다고 한다.)

6. package.json에 우리가 설치한 package들이 잘 기록되어있는지 확인

   (개발용 devDependencies,    실제 서비스 dependencies)

7. 강의 폴더에 webpack.config.js 생성 및 아래와 같이 작성

module.exports = {
    
}

8. 강의 폴더에 client.jsx 생성 및 아래와 같이 작성

const React = require('react');
const ReactDom = require('react-dom');

ReactDom.render(<WorldRelay/>, document.querySelector('#root'));

9. 강의 폴더에 index.html 생성 및 아래와 같이 작성

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>끝말잇기</title>
</head>
<body>
    <div id="root"></div>
    <script src="./dist/app.js"></script>
</body>
</html>

10. 강의 폴더에 WorldRelay.jsx 파일 생성 및 작성

//필요로 하는 패키지나 라이브러리 불러오기
const React = require('react');
const {Component} = React;

class WordRelay extends Component{
    state={

    }

    render() {
        return (
            <div>

            </div>
        );
    }
}

//쪼갠 파일에서 쓰는 컴포넌트를 밖에서도 사용할 수 있게 해주는 것. (이것이 노드의 모듈 시스템)
module.exports = WordRelay;

여기서 node module 시스템 처음 봤음. export default ~ 이거랑 다른가. 아무튼 저렇게 module.exports를 해줘야 밖에서 사용할 수 있다고 함.

 

실제로 이제 client.jsx파일을 수정해줘야한다.

const React = require('react');
const ReactDom = require('react-dom');
const WordRelay = require('./WordRelay'); //module.export를 했기 때문에 require로 가져올 수 있다.

ReactDom.render(<WordRelay/>, document.querySelector('#root'));

 

근데 여기서 문제점이 있는데, 위에서 만들었던 index.html에서는 app.js 한개만 사용해야한다. 그게 아니면 기존 방식 처럼 <script src=~></script> <script src=~></script> <script src=~></script> 이렇게 여러 <script>태그를 사용해야하는데 그것을 안하려고 webpack을 사용하는 것이다.

 

11. webpack.config.js 에 아래의 내용 추가

const path = require('path'); //node에 기본적으로 제공해주는 path를 쉽게 조작하기 위한 라이브러리

module.exports = {
    name: 'word_relay-setting', //어떤 것을 위한 웹팩 설정인지
    mode: 'development', //실서비스에서는 production
    devtool: 'eval', //빠르게(개발시에만), 'hidden-source-map' //실서버 배포시에는 저거쓰면됨.
    resolve: {
        extensions: ['.js', '.jsx'] //확장자 적어놓으면 xxx.js, xxx.jsx 알아서 찾아서 빌드한다.
    },
    //여기서 부터가 제일 중요
    //entry : 입력,
    //output: 출력
    entry: {
        app:['./client'] // './WordRelay.jsx' 는 이미 client.jsx에서 불러오고 있기 때문에 굳이 써주지 않아도 된다.
    },
    output: {
        //path.join : 파라미터로 전달된 경로를 합쳐준다.
        //__dirname -> 현재 경로 webpack.config.js가 있는 곳(lecture)
        path: path.join(__dirname, 'dist'), //C:\Users\iLovePC\Desktop\codingapple\zerocho-react-webgame\lecture 에 dist를 더해준다.
        filename: "app.js"
    }
}

 

차이점은 class보다 hooks가 좀 더 간결하다.

 

리렌더 시 차이점

hooks를 사용하면 해당 함수 자체가 재실행된다.

const Gugudan = () => {
	...
}

Gugudan() 함수가 재실행 된다고 생각하면 됨. 하지만 class 컴포넌트를 사용하면 render()함수만 재실행 되었다.

그래서 리렌더 시 hooks를 사용한 함수 컴포넌트가 좀 더 느릴 순 있다.

 

JSX에서 HTML 태그와 차이점

class -> className

for(label) -> htmlFor

 

setState가 여러 번 동시에 일어날 경우?

그렇게되면 리랜더가 여러 번 일어나는 것 아니냐는 걱정 섞인 댓글이 있었다.

하지만 이러한 경우 React가 알아서 setState를 모아서 한번에 처리 후 리랜더는 한번만 일어난다고 한다.

const onSubmit = (e) => {
                e.preventDefault();
                const ans = first * second;
                if(parseInt(value) === ans){
                    setFirst(()=>Math.ceil(Math.random() * 9));
                    setSecond(()=>Math.ceil(Math.random() * 9));
                    setValue(()=>'');
                    setResult(()=>`정답 ${ans}`);
                }else{
                    setResult(() => `땡`);
                    setValue(()=>'');
                }
                inputRef.current.focus();
            }

이렇게 setFirst, setSecond, setValue, setResult 처럼 동시에 state 변경을 여러 번 하면 리랜더가 여러번 일어날 줄 알았지만 React가 setState관련 함수를 모아서 한번에 처리하기 때문에 리랜더는 한번만 일어난다고 한다.

Class 문법 사용하지말라?

React 에서 추천하는 방법이 class 를 사용하지말고 Hooks를 사용하라는 것이다.

하지만 class 문법도 알긴해야한다. 실무에 class로 작성된 코드가 있을 수 있기 때문.

 

함수 컴포넌트

//클래스 컴포넌트
class GuGuDan extends React.Component{
	...
}
//함수 컴포넌트
const GuGuDan = () => {
	return (<div>...</div>);
}

원래 함수 컴포넌트에서는 state와 ref같은 것들을 사용하지 못하였다. 그래서 state, ref같은 것이 필요 없는 컴포넌트에서만 함수 컴포넌트를 사용 했었다고 한다.

하지만 점점 많은 사람들이 함수 컴포넌트에서도 state, ref를 사용할 수 있게 해달라고 요청이 많아지자 React 개발팀에서 함수 컴포넌트에서도 state, ref를 사용할 수 있게 만들어 준 것이 바로 React Hooks이다.

 

React Hooks

함수 컴포넌트에 state, ref, useEffect와 같은 기능이 추가 된 것.

use~ 이렇게 use로 시작하는 것들이 Hooks이다.

클래스 컴포넌트를 사용하는 것보다 코드가 간결하고 단순하다.

 

state 선언하기 변화

//함수 컴포넌트(Hooks 사용)
const [value, setValue] = React.useState('');
const [result, setResult] = React.useState('');

//클래스 컴포넌트
state = {
	value: '',
    result: '',
}

 

setState 함수 변화

//React Hooks 사용
const onChange = (e) => {
	setValue(() => {
    	return e.target.value;
	})
};

//클래스 컴포넌트
onChangeInput = (e) => {
	const {value} = e.target;
    this.setState({value});
    console.log(this.state)
};

 

ref 변화

//React Hooks 사용
const inputRef = React.useRef(null); //선언
inputRef.current.focus(); //함수 내에서 사용

//클래스 컴포넌트
onRefInput = (c) => {this.input = c;} //선언
this.input.focus(); //사용

 

전체코드 (React Hooks 사용)

<script type="text/babel">
        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 onChange = (e) => {
                setValue(() => {
                    return e.target.value;
                })
            }
            const onSubmit = (e) => {
                e.preventDefault();
                const ans = first * second;
                if(parseInt(value) === ans){
                    setFirst(()=>Math.ceil(Math.random() * 9));
                    setSecond(()=>Math.ceil(Math.random() * 9));
                    setValue(()=>'');
                    setResult(()=>`정답 ${ans}`);
                }else{
                    setResult(() => `땡`);
                    setValue(()=>'');
                }
                inputRef.current.focus();
            }

            return (
                <React.Fragment>
                    <div>{first} 곱하기 {second}는?</div>
                    <form onSubmit={onSubmit}>
                        <input ref={inputRef} onChange={onChange} type="number" value={value}/>
                        <button>입력</button>
                    </form>
                    <div id="result">{result}</div>
                </React.Fragment>
            );
        }
    </script>
    <script type="text/babel">
        ReactDOM.createRoot(document.querySelector('#root')).render(<div><Gugudan/><Gugudan/><Gugudan/></div>);
    </script>

 

+ Recent posts