Book - 실전 리액트 프로그래밍 / 이재승

Wednesday, September 30, 2020

실전 리액트 프로그래밍 - 이재승

기본정보

  • 프로그래밍 인사이트 2019

감상

입문자를 위한 책이 아니라, 기능에 대해 어느정도 이해한 사람이 찾아보는 용도 또는 관련 기능에 대해 더 알고 싶을때 봐야하는 책이다. 아무것도 모르는 상태에서 이책을 읽는다면 별 도움이 되지 않는다. 리액트로 몇개의 프로젝트를 해본 뒤에 소장해 놓고 보면 좋을 책이다.

리액트 프로젝트 시작하기

  1. createElement 구조
    • React.createElement(component, props, …children) => ReactElement
      • component는 일반적으로 문자열이나 리액트 컴포넌트, component의 인수가 문자열이면 HTML 태그에 해당하는 돔 요소가 생성.
      • Props는 컴포넌트가 사용하는 데이터. 돔 요소의 경우 style, className등의 데이터가 사용될 수 있다.
      • children은 해당 컴포넌트가 감싸고 있는 내부의 컴포넌트를 가리킨다.
    • 대부분의 리액트 개발자는 createElement를 직접 작성하지 않는다. 일반적으로 바벨(babel)의 도움을 받아서 JSX 문법을 사용.
  2. babel
    • 바벨은 자바스크립트 코드를 변환해 주는 컴파일러
    • 바벨을 사용하면 최신 자바스크립트 문법을 지원하지 않는 환경에서도 최신 문법 사용가능
    • 코드에서 주석을 제거하거나 코드를 압축하는 용도로도 사용
    • 리액트에서는 JSX 문법을 사용하기 위해 바벨을 사용
npm install @babel/cli @babel/preset-react
- @babel/cli 에는 커맨드 라인에서 바벨을 실행할 수 있는 바이너리 파일 포함
- @babel/preset-react(리액트 애플리케이션을 만들때 필요한 플러그인을 모아놓은 프리셋)에는 JSX로 작성된 코드를 createElement 함수를 이용한 코드로 변환 해주는 바벨 플러그인 포함
npx babel --watch src --out-dir . --presets @babel/preset-react
- npx 명령어는 외부 패키지에 포함된 실행 파일을 실행할 때 사용된다.
- 외부 패키지의 실행 파일은 ./node_modules/.bin/ 밑에 저장되며 npx babel은 ./node_modules/.bin/babel을 입력하는 것과 비슷
- src 폴더에 있는 모든 자바스크립트 파일을 @babel/preset-react 프리셋을 이용해서 변환 후 현재 폴더에 같은 이름의 자바스크립트 파일을 생성한다.
- watch 모드로 실행하면 src 폴더의 자바스크립트 파일을 수정할 때마다 자동으로 변환 후 저장한다.
  1. webpack
    • 웹팩(webpack)은 자바스크립트로 만든 프로그램을 배포하기 좋은 형태로 묶어주는 툴
    • 웹팩은 ESM(ES6의 모듈 시스템)과 commonJS를 모두 지원한다. 이들 모듈 시스템을 이용해서 코드를 작성하고 웹팩을 실행하면 예전 버전의 브라우저에서도 동작하는 자바스크립트 코드를 만들 수 있다.
// file1.js 파일
export default function func1(){}
export function func2() {}
export const variable1 = 123;
export let variable2 = 'hello';

//file2.js 파일
import myFunc1, { func2, variable1, variable2 } from './file1.js';

//file3.js 파일
import { func2 as myFunc2 } from './file1.js';
- ESM 문법을 익히기 위한 모듈을 내보내고 가져오는 코드
- default 키워드는 한 파일에서 한 번만 사용 가능하며 default로 내보내진 코드는 괄호 없이 가져올 수 있고, 이름은 원하는 대로 정할 수 있다.
- default 키워드 없이 내보내진 코드는 괄호를 사용해서 가져오고, 가져오는 이름은 내보낼때 사용된 이름을 그대로 가져와야 한다.
npm init -y
- 명령어를 실행하면 package.json 파일이 생성
npm install webpack webpack-cli react react-dom
- 외부 패키지 설치(웹팩, 리액트 패키지)
- 리액트 패키지에는 react.production.min.js와 react.development.js 파일이 포함
- react-dom 패키지에는 react-dom.production.min.js와 react-dom.development.js 파일이 포함
- npx webpack 웹팩 실행
  1. 클래스형 컴포넌트와 함수형 컴포넌트

    • 기능적인 측면에서 클래스형 컴포넌트는 함수형 컴포넌트가 할 수 있는 모든 일을 할 수 있다.
    • 리액트 16.8 이전 버전의 함수형 컴포넌트는 상탯값을 가질 수 없고 리액트 컴포넌트의 생명 주기 함수를 작성할 수 없다.
    • 리액트 16.8부터 훅(hook)이라는 기능이 추가되면서 함수형 컴포넌트에서도 상탯값과 생명 주기 함수 코드 작성 가능.
  2. create-react-app

    • 리액트로 웹 애플리케이션을 만들기 위한 환경을 제공
    • 바벨, 웹팩, 테스트 시스템, HMR, ES6+문법, CSS 후처리등 거의 필수라 할 수 있는 개발 환경도 구축
npx create-react-app cra-test

또는

npm install -g create-react-app
create-react-app cra-test
npm start
- HMR : 변경된 파일이 바로 적용 
- npm start는 개발 모드에서 동작
- index.html, index.js파일은 빌드 시 예약된 파일 이름으로 지우면 안된다.
- index.js로부터 연결된 모든 자바스크립트 파일과 CSS파일은 src 폴더 밑에 있어야 한다.
- serviceWorker.js 파일에는 PWA(progressive web app)와 관련된 코드가 들어있다. PWA는 오프라인에서도 잘 동작하는 웹 애플리케이션을 만들기 위한 기술
- PWA 기능을 원하면 index.js 파일에 serviceWorker.register(); 코드를 넣으면 된다.
  1. create-react-app 주요 명령어
    • npm start
      • 개발모드로 프로그램 실행.
      • HMR이 동작하므로 코드 수정시 즉시 반영.
      • API 호출을 위해 https로 실행할때
      set HTTPS=true && npm start
      
      • 자체 서명된 인증서와 함꼐 https 사이트로 접속
    • npm run build
      • 배포환경에서 사용할 파일을 생성
    • npx serve -s build
      • serve 패키지는 노드(node.js) 환경에서 동작하는 웹 서버 애플리케이션
      • 정적 파일을 서비스할 때 사용
      • build/static 폴더 밑에 생성된 파일이 이름에 해시값이 포함되어 새로 빌드를 하더라도 변경되지 않은 파일은 브라우저에 캐싱되어 있는 파일을 사용. 따라서 재방문의 경우 빠르게 페이지가 렌더링
      • 모든 CSS파일은 build/static/css/main.{해시값}.chunk.css 에 저장
      • import 키워드를 이용해 가져온 폰트,이미지등의 리소스 파일은 build/static/media 폴더 밑에 저장
    • npm test
      • 테스트 코드가 실행
      • 제스트(jest)라는 테스트 프레임워크를 기반
      • create-react-app으로 프로젝트를 생성하면 App.test.js 파일이 생성된다.
      • 다음 조건을 만족하면 테스트 파일로 인식
      __tests__ 폴더 밑에 있는 모든 자바스트립트 파일
      파일 이름이 .test.js로 끝나는 파일
      파일 이름이 .spec.js로 끝나는 파일
      
    • npm run eject
      • 내부 설정 파일이 밖으로 노출
      • 이 기능으로 바벨이나 웹팩의 설정을 변경
    • npm install core-js
      • core-js 패키지를 이용한 폴리필
  2. CSS
    • css-module을 사용하면 일반적인 CSS 파일에서 클래스명 충돌을 피할 수 있다.
    • {이름}.module.css 로 파일을 생서하면 css-module이 된다.
    • Sass는 CSS와 비슷하지만 별도의 문법을 이용해서 생산성이 높은 스타일 코드를 작성할 수 있게 한다.
    • Sass 문법에 있는 변수, 믹스인(mixin)등의 개념을 이용하면 스타일 코드를 재사용
    • create-react-app에서 Sass를 사용하고 싶다면 다음 패키지를 설치
    npm install node-sass
    
  3. SPA(Single Page Application)
    • SPA는 최초 요청시 서버에서 첫 페이지를 처리하고 이후의 라우팅은 클라이언트에서 처리하는 웹 애플리케이션
    • SPA 구현을 위해 두 가지 기능이 필요
      • 자바스크립트에서 브라우저로 페이지 전환 요청을 보낼수 있다. 단 브라우저는 서버로 요청을 보내지 않아야 한다.
      • 브라우저의 뒤로 가기와 같은 사용자의 페이지 전환 요청을 자바스크립트에서 처리할 수 있다. 이떄도 브라우저는 서버로 요청을 보내지 않아야 한다.
    • 이러한 조건을 만족하는 브라우저 API는 pushState, replaceState 함수와 popstate 이벤트이다.
    • replaceState 함수는 pushState와 거으 ㅣ같지만 스택에 state를 쌓지 않고 가장 최신의 state를 대체한다.
    • 브라우저 히스토리 API를 이용해서 페이지 라우팅 처리를 직접 구현할 수도 있지만 react-router-dom을 사용하면 도움이 된다.
    npm install react-router-dom
    
    • 웹을 위한 react-router 패키지
    • 같은 path 속성값을 갖는 Route 컴포넌트를 여러 번 작성해도 된다.
    • Route를 통해 렌더링되는 컴포넌트는 match라는 속성값을 사용할수 있다.
    • match.url은 Route 컴포넌트의 path 속성값과 같다.
    • Route 컴포넌트의 path 속성값에서 콜론을 사용하면 파라미터를 나타낼수 있다.
    • 추출된 파라미터는 match.params.{파라미터이름} 형식으로 사용될 수 있다.

ES6+를 품은 자바스크립트

변수를 정의하는 새로운 방법: const, let

  1. var가 가진 문제
    • 함수 scope 문제: var로 정의된 변수의 정의된 위치에 의해 scope이 결정된다. 정의된 함수 밖에서 사용하면 에러 발생. 또는 반복문에 사용된 i가 반복문이 끝난 이후에도 계속 남게 되는 문제점.
    • hoisting: var로 정의된 변수는 그 변수가 속한 scope의 최상단으로 끌어올려진다. 변수의 정의만 끌어올려지고 값은 원래 정의했던 위치에서 할당된다.
  2. var의 문제를 해결하는 const, let
    • const와 let은 블록 스코프
    • 블록 스코프는 블록을 벗어나면 변수를 사용할 수 없다.
    • const는 변수를 재할당 불가능하게 만든다.

객체와 배열을 간편하게 생성/수정

  1. 단축 속성명
    • 새로 만들려는 객체의 속성값 일부가 이미 변수로 존재하면 간단하게 변수 이름만 작성
    • 속성값이 함수이면 function 키워드 없이 함수명만
  2. 전개 연산자
const numbers = [1, 3, 7, 9];
Math.max(...numbers);
- 전개 연산자는 배열이나 객체의 모든 속성을 풀어놓을때 사용하는 문법
- 전개 연산자를 사용하면 동적으로 함수의 매개변수를 전달할 수 있다.
[1, ...[2, 3], 4];  //[1, 2, 3, 4]
- 배열 리터럴에서 중간에 전개 연산자를 사용하면 전개 연산자 전후의 순서가 유지
- Date 생성자의 매개변수 순서대로 날짜 데이터를 관리하면 Date 객체를 쉽게 생성 가능
  1. 배열 비구조화
    • 배열의 여러 속성값을 변수로 쉽게 할당
const arr = [1, 2];
const [a, b] = arr;
console.log(a); // 1
console.log(b); // 2
let a, b;
[a, b] = [1, 2];
  1. 객체 비구조화
    • 객체의 여러 속성값을 변수로 쉽게 할당할 수 있는 문법
const obj = { age: 21, name: 'mike'};
const {age, name} = obj;
consol.log(age);  // 21
consol.log(name);  // mike
- 객체 비구조화에서는 중괄호 사용
- 배열 비구조화에서는 배열의 순서가 중요, 객체 비구조화에서 순서는 무의미
  1. 매개변수 기본값
function printLog(a = 1){
    console.log({a});
}
printLog();  // {a: 1}
- 인수 없이 함수를 호출하므로 a에는 undefined가 입력된다. 기본값이 정의된 매개변수에 undefined를 입력하면 정의된 기본값 1이 사용된다.
  1. 나머지 매개변수
function printLog(a, ...rest){
    console.log({a, rest});
}
printLog(1, 2, 3);  // { a: 1, rest: [2, 3]}
-하나의 인자를 제외한 나머지를 rest 매개변수에 할당
  1. 명명된 매개변수
const numbers = [10, 20, 30, 40];
const result1 = getValues(numbers, 5, 25);
const result2 = getValues({numbers, greaterThan: 5, lessThan: 25});
- result1의 경우 매개변수의 이름이 보이지 않아 인수가 의미하는 바를 알기 어렵다
- result2처럼 명명된 매개변수를 이용하면 매개변수의 이름이 노출된다.
  1. 화살표 함수
    • ES6에서는 화살표 함수를 이용해 함수를 정의하는 방법이 추가되었다.
const add = (a, b) => a + b;
console.log(add(1, 2));  // 3
const add5 = a => a + 5;
console.log(add5(1));  //6
const addAndReturnObject = (a, b) => ({result: a + b});
console.log(addAndReturnObject(1, 2).result); //3
- 화살표 함수를 중괄호를 감싸지 않으면 오른쪽의 계산 결과가 반환(return 키워드 생략 가능)
- 매개변수가 하나라면 매겨변수를 감싸는 소괄호 생략 가능
- 객체를 반환해야 한다면 소괄호로 감싸야 함.
const add = (a, b) => {
    if (a <= 0 || b <= 0 ) {
        throw new Error ('must be positive number');
    }
    return a + b;
}
- 화살표 함수에 여러줄의 코드가 필요하다면 중괄호로 묶고, 반환값에는 return 키워드 사용
- this와 arguments가 바인딩되지 않는다.
  1. promise
    • 프로미스(promise)는 비동기 상태를 값으로 다룰 수 있는 객체
    • 자바스크립트에서 비동기 프로그래밍의 한 가지 방식으로 콜백(callback) 패턴을 많이 사용하나, 콜배깅 조금만 중첩돼도 코드가 상당히 복잡해지는 단점이 있다.
    • 프로미스를 사용하면 비동기 프로그래밍을 할 때 코드를 순차적으로 작성할 수 있다.
    • 프로미스의 세 가지 상태
      • 대기 중(pending): 결과를 기다리는 중
      • 이행됨(fulfilled): 수행이 정상적으로 끝났고 결과값을 갖고 있음.
      • 거부됨(rejected): 수행이 비정상적으로 끝남
      • settle:수행된 상태(성공 또는 실패)
const p1 = new Promise((resolve, reject) => {

});
const p2 = Promise.reject('error message');
const p3 = Promise.resolve(param);
- new 키워드를 사용해서 프로미스를 생성. 이때 대기 중 상태가 된다.
- new 키워드를 사용하지 않고 Promise.reject를 호출하면 거부됨 상태인 프로미스가 생성
- Promise.resolve를 호출해도 프로미스가 생성.
requestData().then(onResolve, onReject);
Promise.resolve(123).then(data => console.log(data));
Promise.reject('err').then(null, error => console.log(error));
- then은 처리됨 상태가 된 프로미스를 처리할 떄 사용되는 메서드
- catch는 프로미스 수행 중 발생한 예외를 처리하는 메서드. then 메서드의 onReject 함수와 같은 역할
- finally는 프로미스가 이행됨 또는 거부됨 상태일 때 호출되는 메서드
- promise.all 병렬로 처리
- promise.race 여러 개의 프로미스 중에서 가장 빨리 처리된 프로미스를 반환
  1. promise 2
    • 동기식 처리 모델: 직렬적으로 task를 수행. 순차적으로 실행되므로 어떤 작업이 수행 중이면 다음 task는 대기
    • 비동기식 처리 모델: 병렬적으로 task를 수행. task가 종료되지 않은 상태라 하더라도 대기하지 않고 즉시 다음 task를 실행
    • 자바스크립트의 대부분의 DOM 이벤트와 Timer함수, Ajax 요청은 비동기식 처리 모델로 동작한다.
    • 자바스크립트는 요청을 병렬로 처리하여 다른 요청이 블로킹 되지 않는 장점이 있다.
    • 비동기 처리를 위해 콜백 패턴을 사용하면 처리 순서를 보장하기 위해 여러 개의 콜백 함수가 네스팅(nesting, 중첩)되어 복잡도가 높아지는 콜백 헬이 발생하는 단점이 있다. 가독성을 나쁘게 하며 실수를 유발.

리액트 개념

  1. 상탯값과 속성값으로 관리하는 UI 데이터
    • UI 데이터는 컴포넌트 내부에서 관리되는 상태값(state)과 부모 컴포넌트에서 내려 주는 속성값(props)으로 구성
    • 리액트는 화면을 그리는 모든 코드는 컴포넌트의 렌더(render) 함수로 작성. UI 데이터가 변경되면 리액트가 렌터 함수를 이용해서 화면을 자동으로 갱신해 주며, 이것이 리액트의 가장 중요한 역할
    • 상태값을 변경해주는 setState 메서드는 비동기로 동작
  2. 리액트 요소와 가상 돔
    • 리액트는 렌더링 성능을 위해 가상 돔을 활용. 메모리에 가상 돔을 올려 놓고 이전과 이후의 가상 돔을 비교하여 변경된 부분만 실제 돔에 반영
    • 리액트에서 데이터 변경에 의한 화면 업데이트는 렌더 단계와 커밋 단계를 거친다.
    • 렌더 단계는 실제 돔에 반영할 변경 사항을 파악하는 단계이고, 커밋 단계는 파악된 변경 사항을 실제 돔에 반영하는 단계
  3. 생명 주기 메서드
    • 모든 컴포넌트는 다음과 같이 세 단계를 거친다. 초기화 단계, 업데이트 단계, 소멸 단계
    • 각 단계 속에서 호출되는 메서드를 생명 주기 메서드라고 부른다.
    • method
    • 렌더링 시 예외가 발생하면 호출되는 메서드
      • static getDerivedStateFromErro()
      • componentDidCatch()
    • constructor 메서드

    constructor(props) { super(props); this.state = { currentMovie: props.age < 10 ? ‘뽀로로’ : ‘어벤져스’, }; }

        + constructor 메서드 내부에서 반드시 super 함수를 호출해야 한다.
        + 상태값을 직접 할당하는 것은 constructor 메서드에서만 허용
        + constructor 메서드 내부에서 호출되는 setState 메서드는 무시된다. setState 메서드 호출은 컴포넌트가 마운트된 이후에만 유효
    - getDerivedStateFromProps 메서드
        + 속성값을 이용해서 새로운 상태값을 만들 때 사용되며 render 메서드가 호출되기 직전에 호출된다.
        + static getDerivedStateFromProps (props, state)
        + 정적 메서드이기 떄문에 함수 내부에서 this객체에 접근할 수 없다.
    - render 메서드
        + 컴포넌트를 정의할 때 화면에 보여질 반환값의 내용을 결정
        + 배열을 반환할 떄 각 리액트 요소는 key 속성값을 갖고 있어야 한다.
        + 리액트 프래그먼트<React.Fragment>를 사용하면 내부의 리액트 요소에 key속성값을 부여하지 않아도 된다.
        + null 또는 bool을 반환하면 아무것도 렌더링하지 않는다.
        + 리액트 포털을 사용하면 컴포넌트의 현재 위치와는 상관없이 특정 돔 요소에 렌더링할 수 있다
    - componentDidMount
        + render 메서드의 첫 번째 반환값이 실제 돔에 반영된 직후 호출된다.
        + render 메서드에서 반환한 리액트 요소가 돔에 반영되어야 알수 있는 값을 얻을 수 있다.
    - shouldComponentUpdate 메서드
        + 성능 최적화를 위해 존재
        + shouldComponentUpdate(nestProps, nextState)
        + 불 타입을 반환 한다. True를 반환하면 render 메서드가 호출
        + 변수 비교를 통해 render 메서드를 호출할지 결정하므로 성능과 관련있다.
    - getSnapshotBeforeUpdate 메서드
        + 렌더링 결과가 실제 돔에 반영되기 직전에 호출
        + 호출 되는 시점에 이전 돔 요소의 상태값을 가져오기 좋다
    - componentDidUpdate 메서드
        + 업데이트 단계에서 마지막으로 호출되는 생명 주기 메서드
        + componentDidUpdate(prevProps, prevState, snapshot)
        + 가상 돔이 실제 돔에 반영된 후 호출
        + 새로 반영된 돔의 상태값을 가장 빠르게 가져올 수 있는 메서드
        + 속성값이나 상태값이 변경된 경우 API를 호출 하는 용도로 사용되기도 한다.
    - componentWillUnmount 메서드
        + 소멸 단계에서 호출되는 유일한 생명 주기 메서드
        + 끝나지 않은 네트워크 요청을 취소, 타이머 해제, 구독 해제 등의 작업을 처리하기 좋다.
    - getDerivedStateFromError, componentDidCatch 메서드
        + 생명 주기 메서드에서 예외가 발생하면 getDerivedStateFromError, componentDidCatch 메서드를 구현한 가장 가까운 부모 컴포넌트를 찾는다.
        + getDerivedStateFromError(error) 에러 정보를 상태값에 저장해서 화면에 나타내는 용도
        + componentDidCatch(error, info) 에러 정보를 서버로 전송하는 용도
    
  4. 콘텍스트 API로 데이터 전달하기
    • 상위 컴포넌트에서 하위 컴포넌트로 데이터를 전달할 때 속성값이 사용되는데 많은 수의 하위 컴포넌트로 전달할 때에는 속성값을 내려주는 코드를 반복적으로 작성해야 하는 문제가 있다.
    • 콘텍스트 API를 사용하면 컴포넌트 중첩 구조가 복잡한 상황에서도 비교적 쉽게 데이터를 전달할 수 있다.
    • React.createContext(defaultValue) => {Provider, Cosumer}
    • 상위 컴포넌트에서는 Provider 컴포넌트를 이용해서 데이터를 전달
    • 하위 컴포넌트에서는 Cosumer 컴포넌트를 이용해서 데이터를 사용. Consumer컴포넌트는 데이터를 찾기 위해 상위로 올라가면서 가장 가까운 Provider 컴포넌트를 찾는다. 찾지 못하면 기본값을 사용
  5. ref 속성값으로 자식 요소에 접근
    • 돔 요소에 직접 접근해야 할때 ref 속성값을 이용하면 자식 요소에 직접 접근할 수 있다.

컴포넌트 작성

  1. 컴포넌트 파일 작성법
    • 코드를 그룹으로 나누고 우선순위에 따라 배치
      • 속성값 타입 정의 코드
      • 상태값 초기화 코드
      • render 메서드를 제외한 나머지 생명 주기 메서드
      • 생명 주기 메서드를 제외한 나머지 메서드
      • render 메서드
      • 컴포넌트 외부에서 정의하는 변수와 함수
    • 속성값 타입 정의 : prop-types
      • prop-types는 속성값의 타입 정보를 정의할 때 사용하는 리액트 공식 패키지
      • 동적 타입의 언어는 큰 규모의 프로그램을 작성할 때 생산성이 오히려 떨어진다.
      • 컴포넌트 사용 시 속성값에 잘못된 타입이 입력되면 콘솔에 에러 메시지 출력
      class MyComponent extends React.Component {
          static propTypes = {
              //리액트 요소
              menu: PropTypes.element,
      
              //렌더 함수가 리턴할 수 있는 모든 것
              description: PropTypes.node,
      
              //Message 클래스로 생성된 모든 객체
              message: PropTypes.instanceOf(Message),
      
              //배열에 포함된 값 중에서 하나를 만족
              menu: PropTypes.oneOfType([PropTypes.number, ProTypes.string]),
      
              //특정 타입만 포함하는 배열
              age: ProTypes.arrayOf(ProTypes.number),
      
              //객체 속성값 타입 정의
              info: PropTypes.shape({
                  color: proTypes.string,
                  weight: proTypes.number,
              }),
      
              //객체에서 모든 속성값의 타입이 같은 경우
              infos: PropTypes.objectOf(PropTypes.number),
          };
      }
      
    • 조건부 렌더링
      const v1 = 'ab' && 0 && 2;  //v1 === 0
      const v2 = 'ab' && 2 && 3;  //v2 === 3
      const v3 = 'ab' || 0;  //v3 === 'ab'
      const v4 = '' || 0 || 3;  //v4 === 3
      
      • &&, || 연산자 모두 마지막으로 검사한 값을 반환
      • && 연산자는 첫 거짓(false) 또는 마지막 값을 반환하고, ||연산자는 첫 참(True) 또는 마지막 값을 반환 한다.
      • 특정 조건을 만족해야 렌더링할 리액트 요소를 && 연산자 끝에 작성하고 앞쪽에는 해당 조건을 작성하는 방식으로 조건부 렌더링을 구현
      • && 연산자를 사용할 때 주의해야 할 점은 변수가 숫자 타입인 경우 0은 거짓이고 문자열 타입인 경우 빈 문자열도 거짓이다.
    • 관심사 분리를 위한 프레젠테이션, 컨테이너 컴포넌트 구분하기
  2. 이벤트 처리 함수 작성
No.1 Hold

Firebase

Book - 아이디어 불패의 법칙 / 알베르토 사보이아