1. 웹팩으로 빌드하기

터미널에 아래와 같이 webpack을 입력하면 된다. 

> webpackwebpack

※만약 webpack 명령어 등록이 되어있지 않다면 ? (아래와 같은 방법으로 해결)

[package.json]

"scripts": {
    "dev": "webpack"
  },

script 부분에 위와 같이 입력 후 터미널에 아래와 같이 입력한다.

> npm run dev

 

해당 방법도 안되면 npx 사용

> npx webpack 

 

asset app.js 1.59 KiB [emitted] (name: app)
./client.jsx 250 bytes [built] [code generated] [1 error]

ERROR in ./client.jsx 5:16
Module parse failed: Unexpected token (5:16)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concep

word_relay-setting (webpack 5.91.0) compiled with 1 error in 75 ms

webpack으로 빌드하면 위와 같이 아래가 발생하는데 위 에러는 client.jsx의

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

해당 코드에서 발생하는 것이다. 전에 실습할 때도 말했듯 js에서는 '<','>' 해당 문자열을 인식하지 못한다. (JSX문법 이해하지 못함.) 그래서 바벨을 사용해야한다.

바벨이 jsx문법을 react.createDom 같은 문법으로 바꿔줌.

 

2. 바벨 설치하기

npm i -D @babel/core : 바벨의 기본적인것

npm i -D @babel/preset-env : 최신 문법을 예전 브라우저 문법에 맞게 바꿔준다.

npm i -D @babel/preset-react : jsx같은 문법을 지원하는 문법으로 바꿔준다.

npm i -D babel-loader : 웹팩과 바벨을 연결

※ @babel/plugin-proposal-class-properties 나는 추가 안해도 되긴했음. (강의에서는 추가해야만 바벨이 원활하게 작동함)

 

[-D 옵션]

개발할 때만 바벨을 사용하기 때문에 -D 옵션을 준다.

 

3. 웹팩과 바벨 연결하기

웹팩과 바벨을 연결 해주는 babel-loader를 설치했으니 webpack.config.js에 문법에 맞게 입력하면 웹팩과 바벨을 연결할 수 있다.

module:{
	rules:[{
    	test: /\.jsx?/,
        loader: 'babel-loader',
        options:{
        	presets:['@babel/preset-env', '@babel/preset-react'],
            //plugins: ['@babel/plugin-proposal-class-properties']
        }
    }]
}

 

entry에 있는 파일을 읽고 거기에 module을 적용한 후 output에 뺀다. 라는 의미로 알고 있으면 될 것 같다.

-rules는 여러 개를 적용할 수 있어서 배열로 작성한다.

-test는 rule을 적용할 파일들 (위의 예시에서는 js와 jsx에 적용하겠다는 정규식)

-loader : 어떤 규칙을 적용할지 작성한다. (예시에서는 바벨 로더를 적용한다라는 의미라고 함.)

-options는 바벨의 옵션들 (option에 있는 plugins는 안써도 에러가 나지 않아서 주석처리해놓음. 관련된 에러가 나면 추가해주면 될듯)

 

이제 터미널에서 다시 해당 명령어를 입력해주면 build가 정상적으로 될 것이다.

(output에 명시된 규칙대로 잘 나왔는지 확인해보면 된다.)

> webpack

혹은 > npx webpack

 

webpack.config.js 전체코드

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

module.exports = {
    name: 'word_relay-setting', //어떤 것을 위한 웹팩 설정인지
    mode: 'development', //실서비스에서는 production
    devtool: 'eval', //빠르게
    resolve: {
        extensions: ['.js', '.jsx'] //확장자 적어놓으면 xxx.js, xxx.jsx 알아서 찾아서 빌드한다.
    },
    //여기서 부터가 제일 중요
    //entry : 입력,
    //output: 출력
    entry: {
        app:['./client'] // './WordRelay.jsx' 는 이미 client.jsx에서 불러오고 있기 때문에 굳이 써주지 않아도 된다.
    },

    //webpack과 연결할 모듈들을 적시한다.
    module: {
        rules:[{
            test: /\.jsx?/,
            loader: 'babel-loader',
            options:{
                presets:['@babel/preset-env', '@babel/preset-react'],
                //plugins: ['@babel/plugin-proposal-class-properties']
            }
        }],
    },
    output: {
        //path.join : 파라미터로 전달된 경로를 합쳐준다.
        //__dirname -> 현재 경로(lecture)
        path: path.join(__dirname, 'dist'), //C:\Users\iLovePC\Desktop\codingapple\zerocho-react-webgame\lecture 에 dist를 더해준다.
        filename: "app.js"
    }
}

 

다시 한번 복습

웹팩의 사용 이유

-entry에 있는 여러 파일들을 module의 rules를 적용시켜 output에 적힌 규칙대로 합쳐준다.

-난독화도 시켜준다.

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>

 

ref

현재까지는 state를 바꾸면 React가 알아서 화면을 변경해줬다. 그래서 우리가 직접 DOM을 참조할 필요가 없었지만 만약에 input에 focus를 주고 싶은 경우에는 어떻게 할까?

 

기존 바닐라에서는 아래와 같이 하면 됐다.

document.querySelector("input").focus();

하지만 React에서는 대부분 document.querySelector를 사용하지 않는다.

React가 화면을 컨트롤 할 수 있게 해주는 것이 중요하다. 

최대한 React가 제공해주는 것을 사용하자. 이때는 ref를 사용하면 된다.

 

input;

return (
...
<input ref={(c)=>{this.input = c;}} type="number" />
...
)

input을 선언하고, jsx에서 ref={(c) => {this.input = c; }}

 

input을 사용할 때는 js 부분에서 아래와 같이 사용 가능.

 

this.input.focus();

>>>> 따로 메서드로 빼면 아래와 같이 간편해진다.

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

return (
	...
	<input ref={this.onRefInput} type="number" />
    ...
);

 

 

state를 변경했을 때 일어나는 일

setState를 할 때 reder()함수가 재호출되면서 리렌더가 일어난다.

해당 개념이 중요한 이유는 나중에 렌더를 너무 많이 하면 느려진다. render에 10초 걸리는 작업이 있다고 하면 state를 변경할 떄마다 10초씩 걸린다고 생각하면 된다.

 jsx부분의 onChange, onSubmit, ref 이런 부분도 모두 render()함수 위의 js 부분에 선언하는 것이 좋은 이유이다. 만약에 jsx 부분에 inline으로 onChange, onSubmit과 같은 함수를 작성해버리면 state를 변경할 때마다 똑같은 함수가 계속 생기게 된다. (state를 변경하면 render()가 재호출되기 때문)

함수형 setState

setState에 함수를 넣고 그 안에서 새로운 state를 리턴을 하는 것.

함수형 setState 구조

this.setState((prevState)=>{
	return {
    	first: Math.ceil(Math.random() * 9),
        second: Math.ceil(Math.random() * 9),
        value:'',
        result : '정답',
        prevAns : prevState.value,
	}
});

함수형 setState와 기존 setState의 차이점

예전 state값을 다음 state 값에 활용 가능.

기존 state 바꾸는 방식으로 하면 비동기 문제가 생긴다.

this.setState({
    value: this.state.value + 1,
});
this.setState({
    value: this.state.value + 1,
});
this.setState({
    value: this.state.value + 1,
});

이렇게 setState를 3번 호출 하면 this.state.value에 +3이 된 값이 들어있어야 하는데, setState가 비동기라 바로 적용되지 않아서 +1만 되는 경우가 생길 가능성이 크다. 

그렇기 때문에 setState를 할 때는 그냥 함수형으로 사용하자. (특히, 기존 state값을 활용할 경우에는 꼭)

Fragment

React에서 화면을 최종적으로 반환할 때는 딱 하나의 태그만 반환해야한다. (부모 태그가 1개여야한다는 것)

그래서 쓸데없는 <div></div> 로 감싸줘야하는데 이것이 css를 적용할 때 방해가 될 때가 많다.

 

그럴 때 사용하는 것이 빈 껍데기 태그인 <></> Fragment를 사용하는 것이 좋다. 

(이것이 에러나면 <React.Fragment></ React.Fragment>로 감싸주면 된다.)

return (
	<React.Fragment>
    	~
	</React.Fragment>
);

 

클래스 컴포넌트에서 주의점

함수 메서드를 따로 만들어서 이벤트 리스너와 연결시킬 때는 화살표 함수를 사용해라. function을 사용하면 this가 달라져서 작동하지 않는다. 

실무에서는 constructor를 사용하지않고 바로 state= {..} 이렇게 선언한다.

class GuGuDan extends React.Component{
            state = {
                first: Math.ceil(Math.random() * 9),
                second: Math.ceil(Math.random() * 9),
                value:'',
                result : '',
            }

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

            onSubmit = e => {
                e.preventDefault();
                const ans = this.state.first * this.state.second;
                if(ans === parseInt(this.state.value)){
                    this.setState({
                        first: Math.ceil(Math.random() * 9),
                        second: Math.ceil(Math.random() * 9),
                        value:'',
                        result : '정답',
                    })
                }else{
                    this.setState({
                        value:'',
                        result : '땡',
                    });
                }
            }

            render() {
                return (
                    <React.Fragment>
                        <div>{this.state.first} 곱하기 {this.state.second}는?</div>
                        <form onSubmit={this.onSubmit}>
                            <input type="number" value={this.state.value} onChange={this.onChangeInput}/>
                            <button>입력!</button>
                        </form>
                        <div>{this.state.result}</div>
                    </React.Fragment>
                );
            }
        }

 

클래스 문법으로 React 코딩하는 것을 한번 보여준다.
클래스 문법은 진짜 복잡하다.
그래서 JSX가 생김.

class 문법으로 코딩하기 (너무 복잡함)

return e('button', {onClick: () => this.setState({liked: true})}, 'Like');


그래서 JSX가 생김 (좀 더 인간 친화적으로 바뀜)

jsx : javascript + xml

return (
<button onClick={()=>this.setState({liked:true})}>
	Like
</button>
);

 

Babel

하지만 js에서 < 이런 태그 같은거 해석하지 못해서 babel 이라는 라이브러리를 사용해야한다. babel이 <button> 이러한

jsx 태그를 React.createElement 같은 것으로 바꿔준다.

<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>

 

바벨을 사용하는 가장 쉬운 방법은 위의 코드를 붙여넣기하고, 바벨이 바꿔주길 원하는 부분의 <script>를

<script type="text/babel">로 바꿔놓으면 된다.

 

React 규칙

1. 컴포넌트는 대문자로 시작

2. jsx에서 자바스크립트 코드를 사용하기 위해서는 { } 사용 (jsx에서 객체를 생성하려면 {{a:'b', b:'c'}} 이런식으로 해야한다.)

3. jsx에서 html 태그를 사용하기 위해서는 소문자로 사용 (닫는 태그 필수)

4. jsx에서는 if와 for를 사용하지 못한다. if 대신에 삼항연산자, for 대신에 Array.map 을 사용한다.

5. jsx의 return() 에서 최상위 태그는 1개만 존재해야한다. (<> ~ </> Fragment라는 태그를 많이 사용함.)

 

 

React 리액트 기초부터 쇼핑몰 프로젝트까지!

react 공부를 하고싶어서 유료 강의를 사서 보았다.

코딩애플 아저씨 예전부터 유튜브로도 보고 ES6 유료 강의도 봤었는데.. 후기를 리스트 형식으로 간단하게 적어보려고 한다!!

 

 

  1. 설명 이해가 쏙쏙되게 말을 찰지게 하심
  2. 응용이 되게 원리를 설명해주실 때가 많음 → 하지만 막 엄청 깊숙히 설명 해주시지는 않고 딱 간결하게? 오히려 이게 더 좋은거 같기도 하다.
  3. 왜 써야하는지 이유를 설명해주시니 2번과 같이 응용할 때 많은 도움이 된다.
  4. 중요한 것들은 계속 자막으로 반복해서 띄워주셔서 머릿속에 강제로 주입시켜야하는 느낌 (이런것들은 진짜 외워야 원할히 진행가능 할 때 많음..)
  5. 과제를 내줘서 혼자 정리하고 생각할 시간을 주심 → 정답도 있어서 코드 비교 가능★
  6. 5번과 비슷한데 과제를 내주는데 정답에 뭔가 빡치는 문장 써놔서 정답 안보고 풀게 해놓으심..

써놓고 보니 대부분 장점인데.. 그만큼 괜찮은 강의였다.  부가 설명을 하자면

1번 장점은 인상깊은 설명이 props를 설명해주실 때 불륜, 패륜이다.

1번 장점

 

6번 장점은 예를 들면 아래와 같은것들..

6번 장점(?)

누군가에게는 기분이 나쁠수도 있지만 저는 오히려 좋아♥

 

물론 6번은 평소에는 동기부여가 되는 문장을 써주신다.

평상시 정답 문구1
평상시 정답 문구2

 

 

이상입니다아아

+ Recent posts