리액트 2주차 정리

Component Lifecycle

리액트 컴포넌트는 탄생부터 죽음까지, 여러지점에서 개발자가 작업이 가능하도록 메서드를 오버라이딩 할 수 있게 해준다.

Component 생성 및 마운트 (v16.3 이전 버전)

  1. constructor
  2. componentWillMount
  3. render (최초 랜더)
  4. componentDidMount // 이 지점에 제일 많이 뭔가를 써놓는다. 호출하고 타이머걸고 메인함수처럼
class App extends React.Component {
  _interval;

  constructor(props) {
    console.log('App constructor');
    super(props);
    this.state = {
      age: 37,
    };
  }

  componentWillMount() {
    console.log('App componentWillMount');
  }

  componentDidMount() {
    console.log('App componentDidMount');
    this._interval = window.setInterval(() => {
      this.setState({
        age: this.state.age + 1,
      });
    }, 1000);
  }

  componentWillUnmount() {
    console.log('App componentWillUnmount');
    clearInterval(this._interval);
  }

  render() {
    console.log('App render');
    return (
      <div>
        <h2>
          Hello {this.props.name} - {this.state.age}
        </h2>
      </div>
    );
  }
}

Component props, state 변경 (v16.3 이전 버전)

  1. componentWillReceiveProps // 여러 개가 동시에 바뀌었을 때 모아서 한큐에 감. 트랜잭션이라고 볼 수 있겠음
  2. shouldComponentUpdate // boolean 형태의 값을 리턴해야 함. true면 가고 false 리턴시 안 감. 그래서 최적화를 담당. 최적화 필요 있을때만 오버라이드
  3. componentWillUpdate
  4. render
  5. componentDidUpdate
        componentWillReceiveProps(nextProps) {
          console.log(
            `App componentWillReceiveProps : ${JSON.stringify(nextProps)}`,
          );
        }

        shouldComponentUpdate(nextProps, nextState): boolean {
          console.log(
            `App shouldComponentUpdate : ${JSON.stringify(
              nextProps,
            )}, ${JSON.stringify(nextState)}`,
          );
          return true;
        }

        componentWillUpdate(nextProps, nextState) {
          console.log(
            `App componentWillUpdate : ${JSON.stringify(
              nextProps,
            )}, ${JSON.stringify(nextState)}`,
          );
        }

        componentDidUpdate(prevProps, prevState) {
          console.log(
            `App componentDidUpdate : ${JSON.stringify(
              prevProps,
            )}, ${JSON.stringify(prevState)}`,
          );
        }

componentWillReceiveProps

  • props 를 새로 지정했을 때 바로 호출됨
  • 여기는 state 의 변경에 반응하지 않음
    • 여기서 props 의 값에 따라 state 를 변경해야 한다면,
      • setState 를 이용해 state 를 변경함
      • 그러면 다음 이벤트로 각각 가는것이 아니라 한번에 변경됨

shouldComponentUpdate

  • props 만 변경되어도
  • state 만 변경되어도
  • props & state 둘다 변경되어도
  • newProps 와 new State 를 인자로 해서 호출
  • return type 이 boolean임
    • true 면 render
    • false 면 render 가 호출되지 않습니다.
    • 이 함수를 구현하지 않으면, 디폴트는 true

componentWillUpdate

컴포넌트가 재랜더링 되기 직전에 불림 여기선 setState 같은 것을 쓰면 안 됨

componentDidUpdate

컴포넌트가 재랜더링을 마치면 불림

Component 언마운트 (v16.3 이전 버전)

  • componentWillUnmpunt
class Button extends React.Component {
  componentWillUnmount() {
    console.log('Button componentWillUnmount');
  }

  render() {
    return <>hello</>;
  }
}

Component 라이프사이클 변경 (v16.3)

  • Component 생성 및 마운트 (v16.3)

constructor

componentWillMount => getDerivedStateFromProps

render

componentDidMount

  • Component props, state 변경 (v16.3)

componentWillReceiveProps => getDerivedStateFromProps

shouldComponentUpdate

render

componentWillUpdate => getSnapshotBeforeUpdate

(dom에 적용)

componentDidUpdate

  • Component 언마운트 (v16.3)

componentWillUnmount

Component 생성 및 마운트 (v16.3)

  1. constructor
  2. static getDerivedStateFromProps
  3. render (최초 랜더)
  4. componentDidMount
import React from 'react';

class App extends React.Component {
  state = {
    age: 0,
  };

  static getDerivedStateFromProps(nextProps, prevState) {
    console.log(nextProps, prevState);
    if (prevState.age !== nextProps.age) {
      return { age: nextProps.age };
    }

    return null;
  }

  render() {
    console.log('App render');
    return <div>{this.state.age}</div>;
  }
}

export default App;

Component props, state 변경 (v16.3)

  1. static getDerivedStateFromProps​ (props 변경)

  2. shouldComponentUpdate (state 변경)

  3. render

  4. getSnapshotBeforeUpdate

    (dom 에 적용)

  5. componentDidUpdate

import React from 'react';

class App extends React.Component {
  getSnapshotBeforeUpdate(prevProps, prevState) {
    if (prevProps.list.length < this.props.list.length) {
      const list = this.listRef.current;
      return list.scrollHeight - list.scrollTop;
    }
    return null;
  }

  componentDidUpdate(prevProps, prevState, snapshot) {
    if (snapshot !== null) {
      const list = this.listRef.current;
      list.scrollTop = list.scrollHeight - snapshot;
    }
  }

  render() {
    console.log('App render');
    return <div>{this.state.age}</div>;
  }
}

export default App;

Component 언마운트 (v16.3)

  • componentWillUnmount

Component 에러 캐치

componentDidCatch


리액트 프로젝트 구성하기

리액트 라우팅 이해하기

  • Create React App
  • Prettier + ESLint + husky + lint-staged 사용하기
  • 리액트 컴포넌트 디버깅
  • [과제] tic-tac-toe
  • React 의 라우팅 이해하기 (react-router)
  • HOC

Create React App

npx create-react-app 프로젝트명

이렇게 만들면 된다. 예를들면 npx create-react-app tic-tac-toe

npx

  • npm 5.2.0 이상부터 함께 설치된 커맨드라인 명령어
  • 왜 필요?
    • 프로젝트의 로컬에 설치된 패키지의 실행 커맨드를 사용하려면,
      • package.json 의 npm scripts 에 명령어를 추가하여 사용해야 했다.
      • npx 로 바로 실행 가능
    • 전역으로 실행하고 싶은 패키지가 있을 경우,
      • npm i -g 를 이용하여, 전역에 꼭 설치해서 사용해야 가능했다.
      • npx 로 최신 버전의 패키지를 받아 바로 실행 가능

package.json

{
  "name": "tic-tac-toe",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "react": "^16.8.6",
    "react-dom": "^16.8.6",
    "react-scripts": "3.0.1"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": "react-app"
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}
  • 리액트 핵심 모듈
    • “react”: “^16.9.0”
    • “react-dom”: “^16.9.0”
  • cra 를 사용하는데 필요한 모듈
    • “react-scripts”: “3.1.2”
  • npm start
    • react-scripts start
    • 개발용 서버를 띄운다
    • 소스 코드가 수정되었을 때, 다시 컴파일 하고 웹페이지를 새로고침한다.
  • npm run build

    • react-scripts build
    • Creating an optimized production build…​
    • Project 폴더 바로 아래 build 라는 폴더가 만들어지고, 그 안에 Production 배포를 위한 파일들이 생성된다.

      • serve 라는 패키지를 전역으로 설치합니다.
      • serve 명령어를 -s 옵션으로 build 폴더를 지정하여 실행합니다. ​-s 옵션은 어떤 라우팅으로 요청해도 index.html 을 응답하도록 합니다.
      npm install serve -g
      serve -s build
      
  • ​npm test
    • ​react-scripts test
    • Jest 를 통해 test code 를 실행한다.
  • ​npm run eject
    • ​react-scripts eject
    • eject 를 이용하면, cra 로 만든 프로젝트에서 cra 를 제거
    • 보통 cra 내에서 해결이 안되는 설정을 추가해야 할 때 하고, 돌이킬 수 없다.

Prettier + ESLint + husky + lint-staged 사용하기

ESLint

오류라던가, 규칙에 맞지 않는 코드 찾아서 표시해준다.

  • 실습

    mkdir eslint-test
    cd eslint-test
    npm init -y
    npm install eslint -D
    npx eslint --init
    
    {
        "env": {
            "commonjs": true,
            "es6": true,
            "node": true
        },
        "extends": "eslint:recommended",
        "globals": {
            "Atomics": "readonly",
            "SharedArrayBuffer": "readonly"
        },
        "parserOptions": {
            "ecmaVersion": 2018
        },
        "rules": { // rule 추가
            "semi": [
                "error",
                "always"
            ]
        }
    }
    

    이후 터미널에서 npx eslint 파일명.js 해보면 찾아주는 걸 볼 수 있음

  • vs코드에서 사용하기
    익스텐션에서 다운받고 설정한다 { "name": "tic-tac-toe", "version": "0.1.0", "private": true, "dependencies": { "react": "^16.8.6", "react-dom": "^16.8.6", "react-scripts": "3.0.1" }, "scripts": { "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test", "eject": "react-scripts eject" }, "eslintConfig": { // 이렇게 "extends": "react-app", "rules": { "semi": [ "error", "always" ] } }, "browserslist": { "production": [ ">0.2%", "not dead", "not op_mini all" ], "development": [ "last 1 chrome version", "last 1 firefox version", "last 1 safari version" ] } }

Prettier

코드 포매터

  • 실습

    mkdir prettier-test
    cd prettier-test
    npm init -y
    npm i prettier -D
    
    • npm prettier 파일명.js 해보면 어떻게 해야하는지 알려준다
    • npm prettier --write 파일명.js 하면 그렇게 교체한다
  • vs코드에서 사용하기
    익스텐션에서 다운받고 설정한다

  • Command + Shift + P 누른 후 Format Document
    “editor.formatOnSave”: true 하면 저장시 정리해줌

husky

커밋 전에 코드가 예쁘게 되었나 확인해준다

mkdir husky-test

cd husky-test

npm init -y

git init

npm i huskey -D
{
  "name": "husky-test",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "husky": { // 여기
    "hooks": {
      "pre-commit": "npm test"
    }
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "husky": "^3.0.8"
  }
}

React 의 라우팅 이해하기 (react-router)

SPA 라우팅 과정

브라우저에서 최초에 ‘/’ 경로로 요청을 하면,
React Web App 을 내려줍니다.
내려받은 React App 에서 ‘/’ 경로에 맞는 컴포넌트를 보여줍니다.
React App 에서 다른 페이지로 이동하는 동작을 수행하면,
새로운 경로에 맞는 컴포넌트를 보여줍니다.

  • 가장 대표적인 라우팅 패키지 react-router-dom npm i react-router-dom

  • 사용법

    // src/App.js
    
    import React from 'react';
    import { BrowserRouter, Route } from 'react-router-dom';
    import Home from './pages/Home';
    import Profile from './pages/Profile';
    import About from './pages/About';
    
    function App() {
    return (
        <BrowserRouter>
        <Route path="/" component={Home} />
        <Route path="/profile" component={Profile} />
        <Route path="/about" component={About} />
        </BrowserRouter>
    );
    }
    
    export default App;
    
    
    • Route 컴포넌트에 경로(path) 와 컴포넌트(component) 를 설정하여 나열해줍니다.

    • BrowserRouter 로 Route 들을 감싸줍니다.

    • 브라우저에서 요청한 경로에 Route 의 path 가 들어있으면 해당 component 를 보여줍니다.

    • 정확히 하려면 exact를 붙인다!!!

    동적 라우팅

    <Route path="/profile/:id" component={Profile} />
    
    
    import React from "react";
    import { BrowserRouter, Route } from "react-router-dom";
    import Home from "./pages/Home";
    import Profile from "./pages/Profile";
    import About from "./pages/About";
    
    function App() {
    return (
        <BrowserRouter>
        <Route path="/" exact component={Home} />
        <Route path="/profile" exact component={Profile} />
        <Route path="/profile/:id" component={Profile} />
        <Route path="/about" component={About} />
        </BrowserRouter>
    );
    }
    
    export default App;
    
    

  props.match.params.id
  import React from "react";

  export default function Profile(props) {
  const id = props.match.params.id;
  console.log(id, typeof id);
  return (
      <div>
      <h2>Profile 페이지 입니다.</h2>
      {id && <p>id 는 {id} 입니다.</p>}
      </div>
  );
  }

카테고리:

업데이트: