티스토리 뷰

제로초님의 React 기본 강좌 강의를 보고 배운 내용을 정리합니다.

https://www.youtube.com/watch?v=V3QsSrldHqI&list=PLcqDmjxt30RtqbStQqk-eYMK8N-1SYIFn

 


 

2-1. React Hooks 사용하기

 

· Functional Component

setState와 ref를 사용하지 않을 때 Functional Component를 사용한다. (Hooks는 아니다.)

const Hello = () => {
  return (
    <div>Hello</div>
  );
}

 

· React Hooks state 사용

Functional Component에서 setStateref를 사용할 수 있도록 만든 것이다.

state 선언

이 방식을 비구조화 할당 또는 구조 분해 할당이라고 부른다.

this.state = {
  first: Math.ceil(Math.random() * 9),
  second: Math.ceil(Math.random() * 9),
  value: '',
  result: '',
};

const [first, setFrist] = 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('');

state 사용

render() {
  return (
    <React.Fragment>
      <div>{this.state.first} 곱하기 {this.state.second} ?</div>
      <form>
        <inputtype="number" value={this.state.value} />
        <button>send</button>  
      </form>
      <div>{this.state.result}</div>
    </React.Fragment>
  );
}

return (
  <React.Fragment>
    <div>{first} 곱하기 {second} ?</div>
      <form>
        <input type="number" value={value} />
        <button>submit</button>
      </form>
    <div>{result}</div>
  </React.Fragment>
);

state 변경

this.setState({
  value: '29',
  result: '30',
});

setValue('29');
setResult('30');

 

· React Hooks ref 사용

onSubmit = (event) => {
  event.preventDefault();
  this.input.focus();
}

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

render() {
  return (
    <React.Fragment>
      <form onSubmit={this.onSubmit}>
        <input ref={this.onRefInput} type="number" />
      </form>
    </React.Fragment>
  );
}

const inputRef = React.useRef(null);

onSubmit = (event) => {
  event.preventDefault();
  inputRef.current.focus();
}

return (
  <React.Fragment>
    <form onSubmit={onSubmit}>
      <input ref={inputRef} type="number" />
    </form>
  </React.Fragment>
);

 


 

2-2. Class와 Hooks 비교하기

 

· Rendering

class는 setState를 통해 값이 변경되면 render만 새로 실행되지만 Hooks는 Component 전체가 새로 실행된다.

(여기서부터 - 여기까지)

/* Class */
class Gugudan extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      first: Math.ceil(Math.random() * 9),
      second: Math.ceil(Math.random() * 9),
      value: '',
      result: '',
    };
  }

  onSubmit = (event) => {
    event.preventDefault();
    if (parseInt(this.state.value) === this.state.first * this.state.second) {
      this.setState((prevState) => {
        return {
          first: Math.ceil(Math.random() * 9),
          second: Math.ceil(Math.random() * 9),
          value: '',
          result: '정답 : ' + this.state.value + ' 딩동댕',
        } 
      });
    } else {
      this.setState((prevState) => {
        return {
          value: '',
          result: '정답 : ' + prevState.value + ' 띵똥땡',
        } 
      });
    }
    this.input.focus();
  }

  onChange = (event) => {
    this.setState({ 
      value: event.target.value 
    });
  }

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

  // 여기서부터
  render() {
    return (
      <React.Fragment>
        <div>{this.state.first} 곱하기 {this.state.second} ?</div>
        <form onSubmit={this.onSubmit}>
          <input ref={this.onRefInput} type="number" value={this.state.value} onChange={this.onChange} />
          <button>send</button>  
        </form>
        <div>{this.state.result}</div>
      </React.Fragment>
    );
  }
  // 여기까지
}

/* Hooks */
// 여기서부터
const Gugudan = () => {
  const [first, setFrist] = 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 onSubmitForm = (event) => {
    event.preventDefault();
    if (parseInt(value) === (first * second)) {
      setFrist(Math.ceil(Math.random() * 9));
      setSecond(Math.ceil(Math.random() * 9));
      setValue('');
      setResult('정답 : ' + value + ' 딩동댕');
    } else {
      setValue('');
      setResult('정답 : ' + value + ' 띵똥땡');
    }
    inputRef.current.focus();
  }

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

  return (
    <React.Fragment>
      <div>{first} 곱하기 {second} ?</div>
      <form onSubmit={onSubmitForm}>
        <input ref={inputRef} type="number" value={value} onChange={onChangeInput} />
        <button>submit</button>
      </form>
      <div>{result}</div>
    </React.Fragment>
  );
}
// 여기까지

 

· HTML 속성

JavaScript 엔진이 Class Component와 헷갈려하기 때문에 React에서는 HTML 속성으로 class를 사용할 수 없다. 

또한 <label> 태그에 for 속성도 for문과 헷갈려하기 때문에 사용할 수 없다.

class → className

for → htmlFor

 

· state 객체

Hooks에서 state를 객체형으로 사용할 수 있다.

하지만 setState를 통해 값을 변경할 때 모든 state를 지정해주어야 한다.  지정해주지 않은 state는 빈 값이 된다.

state 객체 선언

const [state, setState] = React.useState({
  first: Math.ceil(Math.random() * 9),
  second: Math.ceil(Math.random() * 9),
  value: '',
  result: '',
});

state 객체 사용

<div>{state.result}</div>

state 객체 변경

위 방식일 때는 상관없지만, 아래 방식일 때 지정해주지 않는 first와 second의 state는 빈 값이 된다.

setState({
  first: Math.ceil(Math.random() * 9),
  second: Math.ceil(Math.random() * 9),
  value: '',
  result: '정답 : ' + this.state.value + ' 딩동댕',
});

setState({
  value: '',
  result: '정답 : ' + prevState.value + ' 띵똥땡',
});

 

· return state

함수를 적어 인자 값으로 현재(이전) state를 받을 수 있다. 

setCounter((prevCounter) => {
  return prevCounter + 1
});

 

· 비동기 렌더링

setState를 할 때마다 렌더링이 새로 실행되는데 React는 비동기이기 때문에 아래와 같은 상황에서 4번 렌더링이 아닌 1번만 렌더링이 된다.

if (parseInt(value) === (first * second)) {
  setFrist(Math.ceil(Math.random() * 9));   // 1
  setSecond(Math.ceil(Math.random() * 9));  // 2
  setValue('');                             // 3
  setResult('정답 : ' + value + ' 딩동댕');    // 4
}

 


 

2-3. 웹팩 설치하기

 

· webpack

여러 개의 자바스크립트 파일을 합쳐서 1개의 자바스크립트 파일로 만들어준다.

terminal

// node와 npm 설치된 상태

> npm init
> npm i react react-dom
> npm i -D webpack webpack-cli // 개발에서만 사용할 때 '-D'를 붙힌다.

 

 

TMI !

1. FaceBook에 Component는 2만 개다.

2. 개발자의 원칙은 중복을 제거하는 것이다.

3. node(노드)는 자바스크립트 실행기이다.

 


 

2-4. 모듈 시스템과 웹팩 설정

 

· module

파일을 모듈 시스템으로 만들면 필요한 모듈(파일)만 불러와서 사용할 수 있다.

 

· webpack.config.js

resolve

entry 파일 확장자를 미리 적어서 entry에서 파일 확장자를 적어주지 않아도 된다.

entry

client.jsx에서 WordRelay.jsx를 불러올 경우 입력에 WordRelay를 적어주지 않아도 된다.

output

entry 파일을 한 개의 파일로 합쳐 app.js로 만든다.

const path = require('path');

module.exports = {
  name: 'word-relay-setting',
  // 배포 : production	
  mode: 'development',
  // 배포 : hidden-source-map
  devtool: 'eval',
  resolve: {
    extensions: [
      '.js',
      '.jsx',
    ]
  },
  // 입력
  entry: {
    app: [
      './client',
    //'./WordRelay',
    ]
  },
  // 출력
  output: {
    path: path.join(__dirname, 'dist'),
    filename: 'app.js',
  },
};

 


 

2-5. 웹팩으로 빌드하기

 

· webpack 실행

cmd 창에 webpack 명령어를 입력하면 다음과 같은 오류가 출력된다.

cmd에서 webpack을 실행할 수 있도록 명령어 등록이 필요하다.

 D:\reactjs\react-basic\03. 끝말잇기> webpack
 'webpack'은(는) 내부 또는 외부 명형, 실행할 수 있는 프로그램, 또는
 배치 파일이 아닙니다.

명령어 등록

1. package.json에 scripts 등록

// 부분 생략
{
  "name": "lecture",
  "main": "index.js",
  "scripts": {
  //"명령어": "실행시킬 프로그램"
    "dev": "webpack"
  },
  "author": "BoHee Park",
  "license": "MIT",
}

// npm run 뒤에 scripts에 적어놓은 명령어를 입력한다.
D:\reactjs\react-basic\03. 끝말잇기> npm run dev

2. npx 사용

D:\reactjs\react-basic\03. 끝말잇기> npx webpack

 

· 에러

위 명령어를 입력했을 때, webpack이 jsx 문법을 이해하지 못해 생긴 에러이다.

ERROR in ./client.jsx 6:16
Module parse failed: Unexpected token (6: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/concepts#loaders
| const WordRelay = require('./WordRelay');
| 
> ReactDOM.render(<WordRelay />, document.querySelector('#root'));
 @ multi ./client app[0]

바벨을 install 해주어야 한다.

> npm i -D @babel/core @babel/preset-env @babel/preset-react @babel/plugin-proposal-class-properties babel-loader

 

· babel

webpack에서 jsx를 실행할 수 있도록 babel을 install 한다.

// 부분 생략
{
  "devDependencies": {
  // babel에 기본, 최신 문법을 이전 문법으로 변환 
    "@babel/core": "^7.7.5",
  // browser에 맞게 이전 문법 적용
    "@babel/preset-env": "^7.7.6",
  // jsx 지원
    "@babel/preset-react": "^7.7.4",
  // webpack과 babel 연결
    "babel-loader": "^8.0.6",
    "webpack": "^4.41.2",
    "webpack-cli": "^3.3.10"
  }
}

babel 사용

webpack.config.js에서 babel을 사용할 수 있도록 module을 설정한다.

// 부분 생략

const path = require('path');

module.exports = {
  module: {
    rules: [{
    //js와 jsx 파일에 룰 적용
      test: /\.jsx?/,
    //babel 적용
      loader: 'babel-loader',
    //babel에 옵션
      options: {
        presets: [
          '@babel/preset-env',
          '@babel/preset-react',
        ],
        plugins: [
          '@babel/plugin-proposal-class-properties',
        ],
      },
    }],
  },
};

 


 

2-6. 구구단 웹팩으로 빌드하기

 

· 과정

1. npm installl

react와 webpack, babel 등 사용할 외부 모듈을 install 한다.

2. webpack.config.js

3. 코드 작성

4. 빌드

 


 

2-7. @babel/preset-env와 plugins

 

· preset

plugin들의 모음이다.

 

· @babel/preset-env의 option

option

지원할 browser만 설정한다.

사용 이유

browser가 예전 버전일수록 babel에서 최신 문법을 더 이전에 문법으로 바꿔주어야 한다.

그러면, babel의 작업량이 증가해 속도가 느려진다. 

// 부분 생략
module.exports = {
  name: '',
  mode: '',
  devtool: '',
  resolve: {},
  entry: {},
  module: {
    rules: [{
      test: /\.jsx?/,
      loader: 'babel-loader',
      options: {
        presets: [
          [
            '@babel/preset-env',
            {
              targets: {
                browsers: [
                  // 한국에서 점유율이 5% 이하인 브라우저는 지원하지 않는다.
                  '> 5% in KR',
                  // 크롬 버전이 70이라면, 69와 70 버전만 지원한다.
                  'last 2 chrome versions'
                ],
              },
              debug: true,
            }
          ],
          '@babel/preset-react',
        ],
        plugins: [],
      },
    }],
  },
  output: {},
};

using target

@babel/preset-env의 targer 설정 후, 새로 빌드했을 때 cmd를 통해 적용된 target을 알 수 있다.

// targets의 '> 5% in KR'만 적었을 때
// 한국에서 5% 이하의 점유율을 가진 browser를 제외하고 babel이 지원할 browser를 알려준다.

@babel/preset-env: `DEBUG` option

Using targets:
{
  "chrome": "4",
  "ie": "11",
  "samsung": "10.1"
}

browser 설정 참고

https://github.com/browserslist/browserslist

 

browserslist/browserslist

🦔 Share target browsers between different front-end tools, like Autoprefixer, Stylelint and babel-preset-env - browserslist/browserslist

github.com

 

· plugins

확장 프로그램(?)과 비슷하다.

// 부분 생략
const webpack = require('webpack');

module.exports = {
  name: '',
  mode: '',
  devtool: '',
  resolve: {},
  entry: {},
  module: {},
  plugins: [
    // loader의 options의 'debug: true'를 넣어준다.
    new webpack.LoaderOptionsPlugin({ debug: true }),
  ],
  output: {},
};

 


 

2-8. 끝말잇기 Class 만들기

 

· value와 onChange, defaultValue

<input> 태그 속성으로 value를 사용하면 onChange 속성도 사용해야 한다.

<input type="text" value={value} onChange={onChangeInput} />

value 속성을 사용하지 않으면 defaultValue를 넣어주어야 한다.

<input type="text" defaultValue={value} />

 


 

2-9. webpack-dev-server와 hot-loader

 

· webpack-dev-server

webpack.config.js를 읽어서 빌드를 해주고, 그것을 server로 유지한다.

http://localhost:8080/ 주소를 생성해준다.

 

· react-hot-loader

수정할 때마다 자동으로 빌드를 해준다.

 

· 자동 빌드 환경 설정

1. npm install 

> npm i -D react-hot-loader
> npm i -D webpack-dev-server

2. paskage.json의 scripts 수정

// 부분 생략
{
  "scripts": {
    // 이전 "dev": "webpack"
    "dev": "webpack-dev-server --hot"
  },
  "devDependencies": {
    "react-hot-loader": "^4.12.18",
    "webpack-dev-server": "^3.9.0"
  }
}

3. js 수정

const React = require('react');
const ReactDom = require('react-dom');
const { hot } = require('react-hot-loader/root');

const WordRelay = require('./WordRelay');

const Hot = hot(WordRelay);

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

5. webpack.config.js의 plugins와 output 수정

// 부분 생략
module.exports = {
  module: {
    rules: [{
      test: ,
      loader: '',
      options: {
        presets: [],
        plugins: [
          'react-hot-loader/babel'
        ],
      },
    }],
  },
  output: {
    // 실제 경로
    path: path.join(__dirname, 'dist'),
    filename: 'app.js',
    // 가상 경로
    // nodejs의 app.use('/dist', express.static(__dirname, 'dist'))와 유사
    publicPath: '/dist/'
  },
};

 

TMI ! webpack.config.js를 수정하면 server를 종료했다가 다시 실행시켜 주어야 한다.

 


 

2-10. 끝말잇기 Hooks로 전환하기

 

· 브라우저 콘솔 [HMR]와 [WDS]

이전에 자동 빌드를 위해 설치한 모듈에서 브라우저 콘솔 창에 여러 정보를 나타낸다.

[HMR] Hot Module Reload

[WDS] Web Dev Server

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함