React

정은경·2021년 3월 2일
0

👸 Front-End Queen

목록 보기
141/266

Last updated on: 2024-04-13

React

  • 2013년에 페이스북에서 발표한 오픈소스 자바스크립트 프레임워크
  • 리액트 프레임워크는 가상 DOM과 JSX(JavaScript xML)라는 새로운 방식으로 동작하는 프레임워크
  • 리액트는 앵귤러, 뷰와 함께 대표적인 프론트엔드 자바스크립트 프레임워크로 분류됨
  • 리액트는 '싱글 페이지 애플리케이션을 만드는 프론트엔드 자바스크립트 라이브러리'라고 소개할 수 있음

SPA (Single Page Application)

  • 웹 서버는 웹 브라우저가 요청하는 다양한 유형의 자원(resource)을 제공하는 역할
  • HTTP 요청 -> HTTP 응답 -> Rendering
  • 리액트 프레임워크로 만드는 웹 애플리케이션은 index.html 파일 1개로 동작
  • 따라서 웹서버에 자원을 한 번만 요청하므로 화면 깜빡임 현상이 발생하지 않음
  • 즉, 리액트 프레임워크는 백엔드에서 받은 JSON 데이터를 해석하여 현재 화면에서 사용자가 새로 요청한 부분만 동적으로 화면을 생성

SPA vs. MPA (Multi Page Application)

  • 사용자 요청이 있을 때마다 새로운 html을 전달받는 기존 방식을 멀티 페이지 애플리케이션이라고 함

클라이언트에서 동작하는 템플릿 엔진

  • 서버 쪽 템플릿 엔진의 출력물은 HTML이지만, 프론트엔드 쪽 템플릿 엔진의 출력물은 DOM 객체들의 조합이라는 차이만 있을 뿐, 데이터와 템플릿을 조합하여 출력물을 만들어낸다는 동작 원리는 같음
  • 프론트엔드 프레임워크란 클라이언트(웹 브라우저)에서 동작하는 템플릿 엔진

리액트 버전 18의 특징


타입스크립트 컴파일러 설치하기

npm i -g typescript ts-node
tsc -v
ts-node -v

리액트 프로젝트 만들기

  • 리액트 프로젝트는 create-react-app(이하 CRA)라는 이름의 프로그램으로 만듬

npx (node package manager)

  • npm은 Node.js 프로젝트에서 개발에 유익한 다양한 오픈 소스 라이브러리를 쉽게 설치해 사용할 수 있게 함
  • Node.js 패키지 중에는 라이브러리가 아니라 CRA처럼 독립적으로 실행할 수 있는 프로그램도 있음
  • 프로그램 형태로 동작하는 패키지는 원래 npm i -g 형태로 설치해야 하지만 계속해서 업데이트되므로 최신 버전을 유지하기 번거로움
  • npx는 패키지들의 가장 최신 버전을 찾아내 npm i -g 명령으로 설치해주는 프로그램
npx create-react-app <프로젝트이름> --template typescript

웹팩과 번들 파일

  • 웹팩(webpack)은 프론트엔드 프레임워크에서 사용하는 대표적은 모듈 번들러
  • 웹 애플리케이션은 자바스크립트 코드뿐만 아니라 다양한 이미지 파일, CSS 파일, HTML 파일로 구성되는데, 웹팩에서는 이처럼 애플리케이션이 동작하는 데 필요한 파일을 모듈이라고 함
  • 웹팩은 다양한 입력 모듈을 결합하여 훨씬 단순한 형태의 모듈로 변화해 주는 역할을 함
  • 웹팩의 결과물을 번들(bundle)이라고 함
  • 웹팩은 빌드 모드일 때와 개발 모드일 때의 동작 방식이 서로 다름

빌드 모드로 실행하기

npm run build
  • 웹팩은 프로젝트 디렉터리의 파일을 모두 모아 이름에 main이나 chunk라는 단어가 있는 번들 파일을 만들어줌
  • build 디렉터리가 새로 생겼고 이 폴더에 index.html 파일도 보임
  • 빌드 모드로 실행할 때에 웹팩은 리액트 프로젝트의 다양한 파일들을 입력으로 하여 번들 파일을 몇 개 생성한 다음, public 디렉터리 안에 있는 index.html 파일을 바탕으로 번들 파일들을 반영한 새로운 index.html 파일을 build 디렉터리에 만들어줌
  • 이렇게 만든 build 디렉터리를 nginx나 아파치 서버와 같은 자신의 웹 서버에 올리면 애플리케이션을 사용자에게 바로 서비스할 수 있음
npm install -g server
serve -s build

개발 모드로 실행하기

npm start
  • npm start 명령을 실행하면 서버를 따로 구동하지 않아도 웹브라우저가 실행되고 리액트 애플리케이션이 실행됨
  • 빌드 모드로 실행했을 때와는 다르게, 웹팩이 서버로 동작
  • npm start 명령을 실행하면 npm run build 때와는 다르게 명령이 종료되지 않고 계속 동작함
  • npm start 명령으로 동작한 react-script start가 내부적으로 웹팩을 서버 형태로 구동하기 때문
  • react-scripts start 명령으로 실행된 웹팩 서버는 리액트 프로젝트 디렉터리의 파일들을 빌드하여 번들 파일로 만든 다음, 이를 반영한 index.html 파일을 생성. 그리고 react-scripts가 웹 브라우저를 실행하고 http://localhost:3000 주소로 접속. 그다음 웹팩이 준비해 둔 index.html에서 <scrtips> 태그의 자바스크립트 코드를 실행해 웹 페이지를 화면에 보여줌

개발 모드에서 핫 모듈 교체

  • 개발 모드는 말 그대로 프로젝트를 개발할 때 사용하는 모드

  • 개발 모드의 핵심은 소스코드를 수정하거나 기능을 추가하면 변경 사항이 즉각즉각 웹 브라우저에 반영되어 눈으로 확인할 수 있어서 개발자의 생산성을 높여주는 것. 웹팩은 이 기능을 핫 모듈 교체(Hot module replacement, HMR) 이라고 함

    핫 모듈 교체 (Hot Module Replacement, HMR)

  • 핫 리로딩(hot reloading)이라고도 함

  • 웹팩 서버는 처음 빌드한 번들 파일들을 웹 브라우저 쪽 index.html 파일에 반영. 이와 동시에 프로젝트 디렉터리에 새로운 파일이 생기거나 기존 파일이 삭제, 변경되는지를 감시. 그리고 처음 빌드한 번들과 다른 부분이 생기면 해당 부분만 빌드한 뒤, 이를 웹 브라우저의 자바스크립트 코드에 심어둔 웹팩 코드와 협업하여 변경된 내용을 실시간으로 반영

Node.js용 외부 패키지 설치

  • npm은 package.json 파일이 있는 디렉터리에서 실행하는 명령
  • 프로젝트 구현에 필요한 다양한 오픈소스 패키지를 npm install 또는 간단히 npm i 명령으로 실치할 수 잇음
  • 설치 명령 옵션
    • --save 또는 -S
      • 실행에 필요한 패키지 설치. package.json 파일의 "dependencies" 항목에 등록됨
    • --save-dev 또는 -D
      • 개발에 필요한 패키지 설치. package.json 파일의 "devDependencies" 항목에 등록됨
  • Node.js 패키지는 자바스크립트로 개발된 것도 있고 타입스크립트로 개발된 것도 있음. 만약 자바스크립트로 개발된 패키지를 타입스크립트에 사용하려면 @types/로 시작하는 타입 라이브러리를 추가로 설치해줘야함

그럴듯한 가짜 데이터 만들기

npm i change luxon
npm i -D @types/chance @types/luxon

리액트 동작 원리

1. 가상 DOM 이해하기

React 17버전 vs. React 18버전


react와 react-dom 패키지

  • 리액트 프로젝트는 항상 react와 react-dom 패키지가 필요
  • react는 리액트 앱이 동작하는 환경과 무관하게 공통으로 사용하는 기능을 제공하는 패키지
  • 반면, react-dom/client를 비롯하여 react-dom/server,react-naitive 조합으로 만든다는 것을 보여줌
  • react와 랜더러 패키지의 경계에는 가상 DOM이라는 메커니즘이 자리 잡고 있음

리액트 패키지 구조
react : 컴포넌트, JSX, 리액트 훅 등 렌더러에 무관한 긴으
|
가상 DOM ---> react-dom/client : CSR 방식 웹 앱
---> react-dom/server : SSR 방식 웹 앱
---> react-native : 모바일앱(아이폰, 안드로이드), 대상앱에 특화된 렌더링 기능

XML 마크업 언어 (eXtensible Markup Language)

  • 쉽게 작성할 수 있고 컴퓨터도 그 의미를 쉽게 파악할 수 있는 특수한 형식의 텍스트
<Person name="Jack" age="32" />
  • 웹 분야에서 문서(document)는 마크업 언어로 작성한 텍스트가 담긴 파일이나 인터넷망을 통해 전송되는 스트림(stream)을 의미
  • 즉, XML 형식으로 작성한 문자열은 XML 문서, HTML 형식으로 작성한 문자열은 HTML 문서라고 함. 이 관점에 따르면 XML이나 HTML 규격을 따르지 않는 문자열이 담긴 파일이나 스트림은 문서라고 하지 않음

문서 객체 모델 (Document Object Model, DOM)

  • 웹 브라우저는 HTML 형식의 문자열을 화면에 출력할 때 문자열을 분석(parsing)하여 어떤 특별한 형식의 자바스크립트 객체 조합으로 바꿈
  • 이 특별한 형식의 자바스크립트 객체는 모두 자신의 특징에 맞는 인터페이스를 구현하는 데, 이들 인터페이스를 총칭하여 문서 객체 모델이라고 함
  • 웹 브라우저의 자바스크립트 엔진은 window라는 이름의 전역 변수를 기본으로 제공
  • 여기서 window는 웹 브라우저의 특정 웹 페이지를 의미하는 객체
  • window 객체는 Window 타입 객체로서 Window 타입을 브라우저 객체 모델(Browser Object Model, BOM) 이라고 함
  • Document 객체

    • 웹 페이지가 HTML 문서를 화면에 출력할 때 window 객체는 document라는 이름의 속성 객체로 HTML 문서 기능을 사용할 수 있게 해줌
    • HTML 문서의 html 요소는 오직 1개만 있어야 하므로, window.document(혹은 줄여서 그냥 document)는 html 요소를 의미
  • document.head와 document.body 객체

    • HTML 문서의 html 요소는 head와 body 태그를 각 1개씩만 가질 수 있음
    • document 객체는 이런 조건에 맞추어 head 요소를 의미하는 head 속성 객체와 body 요소를 의미하는 body 속성 객체를 제공
  • document.createElement 메서드

    • 인터페이스는 객체가 제공해야 할 여러 기능을 구체적으로 정의한 규약(specification)
    • 웹 브라우저는 DOM의 다양한 인터페이스를 각각의 목적에 맞게 구현한 객체로 생성할 수 있도록 document.createElement 메서드를 제공
  • HTMLElement 인터페이스

    • HTMLElement는 모든 종류의 HTML 요소가 구현하는 인터페이스
    • 일부 요소는 이 인터페이스를 직접 구현하기도 하지만, 대부분 HTMLElement를 상속한 자신들이 인터페이스를 구현
    • 인터페이스 이름이 얼핏 복잡해 보이지만 HTML요소명Element 형태의 이름 규칙을 발견할 수 있음
  • HTMLElement의 부모 요소 상속 구조

    HTMLElement의 부모 인터페이스 상속 구조
    EventTarget <-- Node <-- Element <-- HTMLElement

    • HTMLElement의 부모 인터페이스인 Node는 appendChild 메서드를 제공
    • HTMLElement는 모든 HTML 태그의 부모 인터페이스이므로 모든 HTML 태그는 appendChild 메서드를 가짐

자바스크립트만 사용하는 프론트엔드 개발 (물리 DOM)

리액트를 사용하는 프론트엔드 개발 (가상 DOM)

  • 화면에 무엇인가를 보이게 하는 것을 렌더링이라고 하는데, 리액트에서 가상 DOM 객체의 렌더링은 react-dom 렌더러가 수행
  • 리액트는 React.createElement 함수로 다양한 HTML 요소를 가상 DOM 트리 구조로 구현한 뒤, render 메서드가 호출되는 순간 이 가상 DOM 트리를 물리 DOM 트리로 변환해 줌

임의의 물리 DOM 트리에서 일부 HTML 요소의 속성값이 변경될 때 이름 탐지하여 DOM 트리에 반영할 수 있는가?

  • 사실 이 문제는 물리 DOM 세계에서는 일어나지 않음. 속성 값을 바꿔야하는 HTML 요소를 document.getElementById('아이디')로 찾아 해당 요소의 DOM 객체를 얻은 뒤, DOM 객체가 제공하는 속성이나 메서드로 원하는 작업을 하면 그만이기 때문
  • 정작 문제는 '아이디' 부분에 있음. 즉, HTML 요소를 <p>처럼 간결하게 사용하지 못하고, 항상 <p id='아이디'> 형태로 id속성을 명시해줘야함. 또한 이처럼 id속성값을 부여해야 하는 HTML 요소가 많아질수록 서로 중복되지 않게 아이디값을ㅇ 만드는 것도 쉽지 않음. 리액트는 가상 DOM이라는 개념을 도입하여 이 아이디 문제를 해결하고 있음

2. JSX 구문 이해하기

2-1. React.createElement 호출의 복잡성 문제

  • HTML 코드를 React.createElement 호출로 구현

    import React from 'react'
    import ReactDOM from 'react-dom/client'
    import reportWebVitals from './reportWebVitals'
    
    // HTML 코드를 React.createElement 호출로 구현
    const CE = React.createElement
    
    const rootVirtualDOM = CE('ul', null, [
      CE('li', {key: 'li-1'}, [
        CE('a', {href: 'http://www.google.com', target: '_blank', key: 'a-1'}, [
          CE('p', {key: 'p-1'}, 'go to google')
        ])
      ])
    ])
    const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement)
    root.render(rootVirtualDOM)
    
    // If you want to start measuring performance in your app, pass a function
    // to log results (for example: reportWebVitals(console.log))
    // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
    reportWebVitals()
    • (참고) 각 엘리먼트에 key 속성을 추가하지 않으면 추가하라는 에러 발생
    • 리액트 팀은 이러한 React.createElement 호출의 복잡성을 해결하고자 자바스크립트 언어에는 없는 JSX 기능을 언어 확장(Language extension) 형태로 추가함
    • 이 JSX 기능은 리액트 프레임워크가 널리 사용되게 하는 결정적인 역할을 했음
  • HTML 코드를 JSX로 구현

    import ReactDOM from 'react-dom/client'
    import reportWebVitals from './reportWebVitals'
    
    const rootVirtualDOM = (
      <ul>
        <li>
          <a href="http://www.google.com" target="_blank">
            <p>go to Google</p>
          </a>
        </li>
      </ul>
    )
    const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement)
    root.render(rootVirtualDOM)
    
    // If you want to start measuring performance in your app, pass a function
    // to log results (for example: reportWebVitals(console.log))
    // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
    reportWebVitals()
    • JSX 코드는 자바스크립트 코드라기보다 그냥 HTML처럼 보이는데, 이는 JSX가 자바스크립트 문법에 JSX라는 새로운 문법을 추가한 형태로 동작할 수 있도록 설계되었기 때문

2-2. JSX = JavaScript + XML

  • JSX는 'JavaScript XML'의 줄임말로 XML 구문에 자바스크립트 코드를 결합하는 용도로 만들어진 구문
  • JSX는 React.createElement 호출 코드를 간결하게 하려고 고안한 것으로, 자바스크립트 언어를 확장하는 방식으로 구현되었음
  • "자바스크립트 언어를 확장하다"는 의미는 표준 ESNext 자바스크립트나 타입스크립트 문법 자체에는 JSX 구문이 없다는 의미
  • 리액트 제작사인 페이스북은 마치 JSX 구문이 표준 자바스크립트 문법에 포함되어 있는 것처럼 동작하도록 설계
  • XML 용어 알아보기
    • XML 규약 용어
      <div id="root" style="display:flex"><h1>Hello</h1></div>
      --  ------------------------------  ------------   ---
      시작태그    속성                        자식요소         끝태그
  • XML(혹은 HTML5) 표준 준수
    • 리액트의 JSX 구문 분석기는 웹 브라우저의 그것과는 전혀 무관
    • 웹브라우저의 HTML 구문 분석기는 HTML4 등 하위 호환성(backward compatibility)을 보장하므로 XML 규약에 조금 어긋나게 HTML을 작성해도 되지만, 리액트에서 JSX 구문을 작성할 때는 XML 규약을 엄격하게 준수해야함
  • JSX 구문에서 중괄호의 의미
    • XML에 자바스크립트 코드를 삽입하려면 XML 문법에는 없는 기능이 필요
    • JSX는 XML 구조에 중괄호 {}를 사용하여 자바스크립트 코드를 감싸는 형태의 문법을 제공
    • JSX 구문에서 중괄호 안의 자바스크리브 코드는 반드시 return 키워드 없이 값만을 반환해야 함
    • return 키워드 없이 값을 반환하는 구문을 타입스크립트(혹은 EXNext 자바스크립트)에서는 '표현식'이라고 함

2-3. 표현식과 실행문, 그리고 JSX

  • 표현식(expression)
    • 표현식이란 return 키워드 없이 어떤 값을 반환하는 코드를 뜻함
    • 프로그래밍 언어에서 표현식이란 1, true, 'Hello world!'처럼 값으로 평가되는 어떤 것
    • 표현식이란 1+1과 같은 코드 조각, 함수 호출로 반환되는 값 등 값이 될 수 있는 모든 것을 의미함
  • 실행문(execution statement)
    • 실행문은 그 자체로는 '값'이 아님
  • JSX
    • JSX 코드를 구성하는 한 줄 한 줄 모두 React.createElement 호출 코드로 변환되어야함

2-4. 배열과 JSX 구문

  • JSX 구문은 React.createElement 함수 호출을 간결하게 할 목적으로 만들어짐
  • 즉, JSX 구문은 단수화된 React.createElement 호출이므로 반환값은 가상 DOM 객체임. 따라서 변수나 배열에 담을 수 있음
  • 배열을 JSX 문으로 만들 때 주의 사항
    • JSX 문에서 자식 컴포넌트가 여러 개일 때는 반드시 XML 작성 원칙을 준수해야함
    • XML 문법에서 XML 요소는 부모 없이 존재하지 못함
  • 데이터 배열을 컴포넌트 배열로 만들기

3. 컴포넌트 이해하기

3-1. 컴포넌트란?

  • 컴포넌트(component)는 객체지향 언어의 원조인 스몰토크(Smalltalk)에서 유래한 매우 오래된 용어
  • 스몰토크에서 컴포넌트는 화면 UI를 처리하는 클래스를 의미
  • 스몰토크 설계 이론에 따르면 컴포넌트는 모델-뷰-컨트롤러(model-view-controller, MVC) 설계 지침에 따라 구현된 클래스여야함
  • 여기서 모델은 앱의 데이터 부분, 뷰는 모델을 화면에 렌더링하는 부분, 컨트롤러를 사용자의 키보드와 마우스 입력을 수신받아 모델과 뷰에 적절한 형태로 반여하는 역할을 하는 부분을 의미
  • 리액트는 16.8 버전 이후 리액트 훅(react hooks) 이라는 새로운 메커니즘을 고안해 내면서 객체지향 언어에서 의미하는 클래스가 아니라 단순한 함수 형태로 컴포넌트를 구현할 수 있게 되었음
  • 리액트 팀은 가능한 한 함수 컴포넌트와 리액트 훅을 사용하라고 권함

3-2. 리액트 컴포넌트와 사용자 컴포넌트

  • 리액트에서 컴포넌트라는 용어는 구체적으로 2가지 의미를 포함함
    1. 리액트 프레임워크가 제공하는 리액트 제공 컴포넌트(줄여서 리액트 컴포넌트)
    1. 사용자가 구현하는 사용자 정의 컴포넌트(줄여서 사용자 컴포넌트)
  • 리액트 컴포넌트
    • 리액트는 HTML5의 각 태그에 대응하는 리액트 컴포넌트를 제공함
  • 사용자 컴포넌트
  • 사용자 컴포넌트는 왜 구현하는가?
    • 사용자 컴포넌트를 만드는 이유는 React.createElement 호출이나 JSX 문으로 생성하는 가상 DOM 생성 코드를 사용자 컴포넌트 쪽으로 이동하여 코드를 간결하게 하려는 데 목적이 있음

3-3. 클래스 컴포넌트 만들기

  • 리액트에서 클래스 컴포넌트는 반드시 react 패키지가 제공하는 Component 클래스를 상속해야 함
  • Component를 상속한 클래스 컴포넌트는 render라는 이름의 메서드를 포함해야 하며, render 메서드는 null이나 React.createElement 호출로 얻은 반환값, 또는 JSX문 등으로 가상 DOM 객체를 반환해야 함. 여기서 null 값은 '반환할 가상 DOM 객체가 없다'는 의미
import {Component} from 'react'

export default class ClassComponent extends Component {
	render() { return null }
}
  • JSX 구문만으로는 부족한 로직 추가하기

    • 컴포넌트 개념을 도입하면 render 메서드에 JSX 구문 뿐만 아니라 다양한 로직을 타입스크립트 코드와 함께 구현할 수 있음
  • 속성이란?

    • 속성(property)은 객체지향 프로그래밍에서 클래스의 멤버 변수를 의미
    • 컴포넌트 또한 화면 UI를 담당하는 클래스이므로 속성을 가질 수 있음
    • 클래스의 속성은 그 값이 수시로 바뀔 수 있음
    • 수시로 값이 바뀔 수 있는 것을 '가변(mutable)하다 라고함
    • 값이 한 번 설정되면 다시는 바뀌지 않는 것을 '불변(immutable)하다' 고함
    • 리액트 프레임워크에서 속성은 객체지향 언어의 속성과는 다른 부분이 있어서 주의해야함
    • 리액트 프레임워크에서 속성은 부모 컴포넌트가 자식 컴포넌트 쪽에 정보를 전달하는 목적으로 사용됨
    • 참고로, 리액트에서 객체지향 관점의 속성은 상태(state) 라고 함
    • 객체지향 프로그래밍에서 클래스의 속성은 값을 저장하고 변경할 수 있는 기능만 함
    • 반면에 리액트에서 속성은 값이 변하면 해당 컴포넌트를 다시 렌더링하여 수정된 속성 값을 화면에 반영하는 기능도 함
    • 즉, 리액트 컴포넌트 관점에서 속성은 객체지향 프로그래밍 속성 + 재렌터링 을 의미하는 객체 타입 변수
  • JSX 속성 설정 구문

    • JSX는 XML이므로 모든 속성은 작은따옴표로 감싸야함
    • 즉, XML 관점에서 속성은 모두 string 타입임
    • 속성은 XML과 같은 마크업 언어에서는 'attribute'를, 타입스크립트와 같은 프로그래밍 언어에서는 'property'를 의미함
    • JSX는 XML을 확장한 것으로 string 타입 속성은 name='Jack' 형태로 값을 설정할 수 있음, age와 같은 number 타입은 문자열이 아니므로 중괄호 {}로 감싸야함
  • ClassComponent에 속성 구현하기

    import {Component} from 'react'
    
    export type ClassComponentProps = {
        href: string
        text: string
    }
    export default class ClassComponent extends Component<ClassComponentProps> {
        render() {
            const {href, text} = this.props
            return (
                <li>
                    <a href={href}>
                        <p>{text}</p>
                    </a>
                </li>
            )
        }
    }

3-4. 함수 컴포넌트 만들기

  • 리액트 개발팀은 클래스 컴포넌트의 render 메서드 부분을 간단히 함수로 만들 수 있게 함. 이를 함수형 컴포넌트(functional component) 라고함. 그러나 '함수형'이라는 이름의 모호함 때문에 리액트 개발자들은 어느 순간 좀 더 간결하게 '함수 컴포넌트(function component)' 라고 부르기 시작함
  • 함수 컴포넌트의 가장 큰 장점은 상용구 코드가 없기 때문에 컴포넌트를 좀 더 간결하게 구현할 수 있따는 것
export default function App() {
	return <h1>function component</h1>
}

4. key와 children 속성 이해하기

4-1. key 속성 설정하기

  • key 속성은 같은 이름의 컴포넌트가 여러 개일 때 이들을 구분하려고 리액트 프레임워크가 만든 속성

4-2. children 속성 설정하기

  • children은 <div>처럼 자식 요소를 포함할 수 있는 컴포넌트에서만 사용할 수 있음

  • 즉, <img>, <input>처럼 자식 요소를 포함할 수 없는 컴포넌트에서는 children을 사용할 수 없음

  • PropsWidthChildren 타입과 children 속성

    • 리액트는 17 버전까지는 children 속성을 FC 타입에 포함했지만 18 버전부터는 FC 타입에서 children 속성을 제거함
    • 그리고 PropsWithChildren이라는 제네릭 타입을 새롭게 제공하여 children?: ReactNode 부분을 PropsWithChildren 타입으로 대체
    		import type {FC, PropsWithChildren} from 'react'
    	
    		export type PProps = {}
      const P: FC<PropsWithChildren<PProps>> = props => {
      	return <p {...props} />
      }
      export default P
    • 함수컴포넌트를 정의할 때 PropsWithChildren 타입을 사용하면 Props 타입에 반복해서 children 속성을 추가할 필요가 없어지므로 코드를 좀 더 깔끔하게 유지할 수 있음

5. 이벤트 속성 이해하기

5-1. 이벤트란?

  • 리액트를 비롯하여 화면 UI를 다루는 모든 프레임워크는 사용자가 화면 UI에서 버튼을 누르거나 텍스트를 입력하는 등의 행위가 발생하면 이를 화면 UI를 구현한 코드 쪽에 알려 줘야 함. 이처럼 마우스 클릭, 텍스트 입력과 같은 사용자 행위가 일어날 때 '이벤트(event)'가 발생했다 고 표현함
  • Event 타입
    • 웹 브라우저의 자바스크립트 엔진은 Event 타입을 제공
    • https://developer.mozilla.org/en-US/docs/Web/API/Event
    • Event 타입의 주요 속성
      • type
        : 이벤트 이름으로 대소 문자를 구분하지 않음
      • isTrusted
        : 이벤트가 웹 브라우저에서 발생한 것인지(true), 프로그래밍으로 발생한 것인지(false)를 판단
      • currentTarget
        : 이벤트의 현재 대상, 즉 이벤트 버블링 중에서 이벤트가 현재 위치한 객체
      • bubbles
        : 이벤트가 DOM을 타고 버블링될지 여부를 결정
    • 예) type 속성값이 'click'인 Event 객체 생성하는 예
      // type 속성값이 'click'인 Event 객체 생성하는 예
      new Event('click', { bubbles: true })
  • EventTarget 타입
    • 모든 HTMl 요소는 HTMLElement 상속 타입을 가짐
    • HTMLElement는 최상위 EventTarget 타입을 시작으로 Node, Element와 같은 타입을 상속함
    • HTMLElement의 부모 인터페이스 상속 구조
      HTMLElement --> Element --> Node --> EventTarget
  • 이벤트 처리기
    • EventTarget은 addEventListener, removeEventListener, dispatchEvent라는 메서드 3개를 제공
    • EventListener를 구현하는 메커니즘은 콜백 함수. 이벤트를 기다리는 콜백함수는 이벤트 처리기 (event handler) 라고 함
    • 이벤트 처리기는 이벤트가 발생할 때까지 귀 기울여 기다리다가 이벤트가 발생하면 해당 이벤트를 코드 쪽으로 알려주는 역할을 함
    • addEventListener 메서드는 이벤트 처리기를 추가한다는 의미. 하나의 이벤트에 이벤트 처리기를 여러 개 부착할 수 있는 것을 뜻함
    • addEventListener 사용법
      DOM_객체.addEventListener(이벤트_이름: string, 콜백_함수: (e: Event)=>void)
    • 브라우저 객체 모델의 window 객체는 Window 타입이고 Window 타입은 EventTarget 타입을 상속함. 즉, window 객체는 addEventListener 메서드를 제공
      window.addEventListener('click', (e: Event) => console.log('mouse click occurs.'))
    • 리액트 프로젝트는 항상 public 디렉터리에 index.html 파일에 <div id="root"> 태그를 포함하고 있기에 위의 코드를 아래와 같이 작성할 수 있음
      document.getElementById('root')?.addEventListener('click', (e: Event) => {
          const {isTrusted, target, bubbles} = e
          console.log('mouse click occurs.', isTrusted, target, bubbles)
      })

5-2. 물리 DOM 객체의 이벤트 속성

  • window를 포함한 대부분의 HTML 요소는 onclick처럼 'on' 뒤에 이벤트 이름을 붙인 속성을 제공
  • 이벤트 속성은 addEventListener의 사용법을 간결하게 하는 게 목적이므로 이벤트 속성값에는 항상 이벤트 처리기를 설정해야함
    window.onclick = (e: Event) => console.log('mouse click occurs.')
  • 참고로 옵셔널 체이닝 연산자는 document.getElementById('root')?.onclick = 콜백_함수 처럼 사용값을 설정하는 구문에는 사용할 수 없어 다음과 같은 형태로 구현해야함
    const rootDiv = document.getElementById('root')
    if (rootDiv) {
        rootDiv.onclick = (e: Event) => console.log('mouse click occurs.')
    }
  • addEventListener와 달리 onclick은 가장 마지막에 설정된 콜백 함수를 호출!

5-3. 리액트 프레임워크의 이벤트 속성

  • 리액트 컴포넌트도 on이벤트명 형태로 된 HTML 요소의 이벤트 속성을 제공
  • HTML 요소의 이벤트 속성은 모두 소문자지만, 리액트 코어 컴포넌트의 속성은 onClick, onMouseEnter 처럼 카멜표기법을 사용함
  • 리액트 컴포넌트 이벤트 속성에 설정하는 콜백 함수는 매개변수 e의 타입이 Event가 아니라 리액트가 제공하는 SyntheticEvent 타입을 설정해야하는 차이가 있음
  • 리액트 컴포넌트 관점에서 'synthetic'이라는 용어는 '모든 종류의 이벤트를 종합한' 정도로 의역할 수 있음
  • SyntheticEvent는 BaseSyntheticEvent를 상속하는 타입
interface BaseSyntheticEvent<E = object, C = any = T =any> {
	nativeEvent: E;
	currentTarget: C;
 	target: T;
	preventDefault: void;
	stopPropagation: void;
}

interface SyntheticEvent<T = Element, E = Event> extends BaseSyntheticEvent<E, Event-Target & T, EventTarget> {}
  • 리액트는 물리 DOM에서 일어나는 이벤트를 네이티브 이벤트라고 함

  • BaseSynthetic Event의 nativeEvent 속성은 물리 DOM에서 발생하는 Event의 세부 타입인 PointerEvent와 같은 이벤트 객체를 지정하는 데 사용함

  • currentTarget 속성은 이벤트 버블링 과정에서 현재 이벤트를 수신한 DOM 객체를 알고 싶을 때 사용

  • target 속성은 이벤트를 처음 발생시킨 DOM 객체를 알고 싶을 때 사용

  • EventTarget의 dispatchEvent 메서드

    • DOM의 최상위 타입인 EventTarget은 dispatchEvent 메서드를 제공함
      dispatchEvent(event: Event): boolean;
    • Event 타입 객체는 Event나 SyntheticEvent의 target 속성값이 되는 타깃DOM객체 의 dispatchEvent 메서드를 호출하여 이벤트를 발생시킬 수 있음
      타킷_DOM_객체.dispatchEvent(new Event('click', {bubbles: true})
    • 모든 DOM 객체의 부모 타입인 HTMLElement는 click 메서드를 제공함
    • dispatchEvent와 click 메서드로 발생한 이벤트는 isTrusted값이 false
  • 이벤트 버블링 (event bubbling)

    • 이벤트 버블링이랑 자식 요소에서 발생한 이벤트가 가까운 부모 요소에서 가장 먼 부모 요소까지 계속 전달되는 현상
    • currentTarget은 이벤트의 현재 대상, 즉 이벤트 버블링 중 현재 이벤트가 위치한 객체를 가리킴
  • stopPropagation 메서드와 이벤트 전파 막기 (event stop propagation)

    • SyntheticEvent의 부모인 BaseSyntheticEvent 타입이 제공하는 stopPropagation 메서드를 사용해서 이벤트 버블링을 중단할 수 있음

5-4. input 요소의 이벤트 처리

  • input은 type 속성값에 따라 화면에 나타나는 모습과 사용자 입력을 얻는 방법이 조금 다름

<button><input type='button'>의 차이

  • 모두 click 이벤트를 발생시킨다는 공통점
  • <button>은 자식요소를 가질 수 있음
  • <input>은 자식요소를 가질 수 없음
  • input의 onChange 이벤트 속성
    • 사용자의 입력이 텍스트라면 change 이벤트가 발생. 이 change 이벤트는 onChange 이벤트 속성으로 얻을 수 있음
      // ChangeEvent<T> 선언문
      interface ChangeEvent<T = Element> extends SyntheticEvent<T>{
          target: EventTarget & T;
      }
  • input 요소의 이벤트 관련 속성들
    // InputHTMLAttributes<T> 속성 정의
    interface InputHTMLAttributes<T> extends HTMLAttributes<T> {
        checked?: boolean | undefined;
        value?: string | ReadonlyArray<string> | number | undefined;
        files: FileList | null;
        onChange?: ChangeEventHandler<T> | undefined;
        ... (생략) ...
    }
  • input의 defaultValue와 defaultChecked 속성
  • <input type="file">에서의 onChange 이벤트 처리

5-5. 드래그 앤 드롭 이벤트 처리

  • 모든 HTMLElement 상속 요소는 draggable이라는 boolean 타입 속성을 제공

  • 드래그 앱 드록 이벤트

    • dragenter
      : 드래그한 요소나 텍스트 블록을 적합한 드롭 대상 위에 올라갔을 때 발생
      (리액트: onDragEnter)
    • dragstart
      : 사용자가 요소나 텍스트 블록을 드래그하기 시작했을 때 발생 (리액트: onDragStart)
    • drag
      : 요소나 텍스트 블록을 드래그할 때 발생 (리액트: onDrag)
    • dragover
      : 요소나 텍스트 블록을 적합한 드롭 대상 위로 지나갈 때 (수백 밀리초마다) 발생 (리액트: onDragOver)
    • dragleave
      : 드래그하는 요소나 텍스트 블록이 적합한 드롭 대상에서 벗어날 때 발생 (리액트: onDragLeave)
    • dragend
      : 드래그를 끝냈을 때 발생 (리액트: onDragEnd)
    • drop
      : 요소나 텍스트 블록을 적합한 드롭 대상에 드롭했을 때 발생 (리액트: onDrop)
  • 리액트는 DragEvent 타입을 제공함. DragEvent 타입에서 가장 중요한 속성은 dataTransfer

  • dataTransfer 속성은 파일을 드롭했을 때는 files 속성으로 드롭한 파일의 정보를 알 수 있음

preventDefault

  • 어떤 사용자가 액션에 따라 이벤트가 발생했을 때 이 이벤트와 관련된 웹 브라우저의 기본 구현 내용을 실행하지 않게 함
  • 웹 브라우저는 기본으로 drop 이벤트가 발생하지 않도록 설계되었음. 이에 따라 drop 이벤트가 발생하려면 dragover 이벤트 처리기에서 preventDefault 메서드를 호출해야함
  • 또한 onDrop 처리기에도 preventDefault 메서드를 호출해 주는 것이 좋음. 만일 파일을 드롭할 때 웹 브라우저는 드롭한 파일을 새로운 창을 열어 보여 주기 때문

컴포넌트 CSS 스타일링

1. 리액트 컴포넌트의 CSS 스타일링

1-1. 컴포넌트 스타일링

  • 부트스트랩 사용해보기
  • 부트스트랩 컴포넌트 구현하기
  • 리액트 className과 htmlFor 속성

1-2. 웹팩과 CSS 파일 임포트

  • 리액트 프로젝트가 내부적으로 사용하는 웹팩은 .css 파일을 좀 더 쉽게 사용할 수 있게 해줌
  • 웹팩은 이미지와 CSS, 자바스크립트 또는 타입스크립트 코드가 혼합된 프로젝트를 서비스하기 좋게 만들어 줌
  • 특히 웹팩은 타입스크립트 코드에서 import문 형태로 CSS 파일을 <link> 태그 없이 이용할 수 있게 해줌

1-3. CSS 기본 구문

  • 소문자 케밥 표기법(kebab case)
    • 예) background-color
  • 벤더 접두사 (vender prefix)
    • 구글, 애플 등 웹브라우저 제작 업체에서 만든 CSS 기능
    • W3C 표준에 없는 비표준 기능

1-4. 선택자란?

  • CSS 선택자(selector)는 CSS 규칙을 적용할 HTML 요소를 정의

  • CSS 선택자의 종류

    • 예) '전체 선택자', '유형 선택자', '클래스 선택자' 등
  • 전체 선택자 (universal selector)

    • * 기호 사용
    • HTML 문서의 모든 태그를 한꺼번에 선택하는 용도로 사용
  • 유형 선택자 (type selector)

    • HTML 태그 일므을 사용하는 선택자
  • 클래스 선택자 (class selector)

    • .클래스명
    • HTML 문서의 태그 중에 class 속성값이 지정한 클래스 이름과 같은 태그를 한꺼번에 선택하는 용도로 사용

1-5. @import 규칙으로 아이콘 사용하기

1-6. style 속성을 사용한 인라인 스타일링

  • HTML 요소는 style이라는 속성에 문자열로 된 CSS 코드를 설정할 수 있음. 렌더링 때 해당 코드가 반영됨
  • 리액트 컴포넌트에서는 style 속성에 설정하는 값은 문자열이 아닌 객체여야 함

1-7. Node.js 패키지 방식으로 아이콘 만들기

  • @import 방식의 한 가지 문제점은 다른 사이트에서 호스팅된 외부 CSS 파일을 가져오므로 네트워크 속도에 영향을 받을 수 있다는 점!

  • 대부분 웹 애플리케이션은 Node.js 패키지 형태로 구현된 CSS 프레임워크를 내장하는 형태로 배포함

  • 웹 안전 글꼴과 fontsource

    • @import 규칙은 웹 안전 글꼴(web safe font) 을 사용해야한다는 제약이 있음
    • 웹 안전 글꼴은 사용자 컴퓨터에 설치되지 않은 때에도 웹 페이지에 항상 올바르게 표시되는 글꼴을 의미
    • 구글이 제공하는 모든 글꼴은 웹 안전 글꼴이므로 @import 규칙을 적용할 수 있음
    • fontsource(fontsource.org)는 구글 글꼴과 같은 오픈소스 웹 안전 글꼴을 패키지 형태 설치해줌
      npm i @fontsource/케밥-표기법-글꼴명
  • 머티리얼 아이콘 설치하기

    • fontsource.org/fonts 웹 페이지에서 material이란 이름이 있는 패키지를 검색하면 사용법을 확인할 수 있음
    npm i @fontsource/material-icons
  • 머티리얼 아이콘 사용하기

    import '@fontsource/material-icons

1-8. Icon 사용자 컴포넌트 구현하기

1-9. Icon 컴포넌트 개선하기

  • 리액트가 제공하는 DetailedHTMLProps와 HTMLAttributes 타입
  • 타입스크립트의 교집합 타입 구문
  • 타입스크립트에서 매개변수 이름 바꾸기

2. 테일윈드 CSS 리액트 프로젝트 만들기

2-1. PostCSS가 탄생한 배경

  • CSS 개발은 역사적으로 브라우저 호환성과 벤더 접두사(vendor prefix) 같은 문제로 어려움을 겪어 왔으며, 이런 어려움을 극복하려고 루비 언어로 만든 Sass/SCSS라는 스타일 언어가 탄생했음
  • Sass/SCSS는 for 반복문과 같은 프로그래밍 언어 기능도 좀 있었고, 벤더 접두사 문제를 해결해 주는 autoprefixer라는 플러그인도 제공해 지금까지 큰 인기를 끌고 있음
  • '모듈화된 CSS'라는 기치를 내걸으며 PostCSS라는 이름의 새로운 스타일 언어와 이를 동작하게 하는 프로그램이 탄생했음
  • PostCSS는 ESNext 자바스크립트의 바벨이 그러하듯이 다양한 플러그인을 자유롭게 장착할 수 있도록 하여, CSS 표준에 추가되기를 요청하는 많은 기능을 표준화 이전에 실험해 볼 수 있게 함. 물론 이 과정에서 PostCSS는 원래 Sass/SCSS 기능이었던 autoprefixer를 PostCSS 플러그인 형태로 만들었음
  • PostCSS는 웹팩이 1차로 만든 CSS를 가공하여 최종 CSS를 생성해 내는 방법으로 동작. 즉, PostCSS는 웹팩의 플러그인이면서 그 자체는 자신의 PostCSS 플러그인을 동작시키는 프로그램
  • PostCSS가 발전을 거듭하자 CSS 디자이너들은 점차 Sass/SCSS보다 PostCSS를 선호하기 시작
  • 테일윈드CSS는 PostCSS 플러그인방식으로 동작하는 진보된 CSS 프레임워크임

2-2. 테일윈드CSS 사용하기

  • 테일윈드CSS는 2017년 11월에 utilify first을 기치로 만든 CSS 프레임워크임

  • 테일윈드CSS는 PostCSS 버전 8의 플러그인 형태로 동작

  • 테일윈드CSS를 바탕으로 한 약 16종의 고수준 CSS 프레임워크가 있다는 장점이 있음

  • PostCSS와 autoprefixer, 그리고 테일윈드CSS 설치하기

    • autoprefixer는 대표적인 PostCSS 플러그인으로 벤더 접두사를 해결해주는 역할을 함. 사용자 CSS가 벤더 접두사를 붙이지 않더라도 후처리 과정에서 자동으로 벤더 접두사가 붙은 CSS를 생성해줌
    • autoprefixer는 테일윈드CSS와 마찬가지로 PostCSS의 플러그인 형태로 동작하므로 auto prefixer 기능을 사용하려면 PostCSS도 함께 설치해야함
    npm i -D postcss autoprefixer tailwindcss
  • 구성 파일 만들기

    • 테일윈드CSS는 PostCSS의 플러그인 형태로 동작하며 PostCSS가 테일윈드CSS를 플러그인으로 동작시키면 postcss.config.js 파일에 테일윈드CSS를 등록해야함
    • 테일윈드CSS는 PostCSS와는 별도로 자신만의 구성 파일이 있어야함
    npx tailwind init -p
  • daisyui 패키지 설치하기

    • 테일윈드CSS는 부트스트랩과 같은 CSS 프레임워크를 쉽게 개발할 수 있게 해주는 저수준 프레임워크
    • 테일윈드를 사용해서 CSS 컴포넌트를 제공하는 테일윈드의 CSS 플러그인 형태로 동작
    npm i -D daisyui
  • @tailwindcss/line-clamp 플러그인 설치하기

    • 테일윈드CSS의 플러그인 이름에 @tailwindcss/라는 접두사가 붙은 패키지는 테일윈드CSS 제작사가 직접 만들어 제공하는 것
  • 테일윈드 구성 파일 수정하기

    • 테일윈드CSS 기능 가운데 사용하지 않는 기능은 npm run build 명령 때 제거해 CSS 크기를 최소활할 수 있게함
    • 이 기능을 사용하려면 tailwind.config.js 파일에 설정해야함
  • 테일위드CSS 기능 반영하기

    • index.css 파일에 3줄 추가해줘야
    @tailwind base;
    @tailwind components;
    @tailwind utilities;
  • 테일윈드CSS 테스트 코드 작성하기

2-3. 색상을 설정하는 방법

  • CSS 색상 모델과 rgb, hsl 함수
    • RGB(red-green-blue) 모델
    • HSL(hue-saturation-light)
  • CSS의 opacity 스타일 속성과 rgba, hsla CSS 함수
    • 불투명도는 알파값 0~1 사이의 소수로 표현
    • 알파값이 0이면 완전히 투명함을, 1이면 완전히 불투명함을 의미함
  • 테일윈드CSS 색상 클래스

2-4. 텍스트를 설정하는 방법

  • CSS는 길이를 표현할 때 픽셀 단위를 사용
  • em, rem이라는 단위 제공
  • 1rem은 'M' 문자 1개 높이이고, 1.25rem은 'M'문자 1개의 1/4 높이를 더한 높이
  • 글자 크기 설정하기
  • 글자 굵기 설정하기
  • 기울임꼴 설정하기
  • 줄바꿈 문자 설정하기
    • 줄바꿈 문자 \n은 HTML에서는 화이트 스페이스 로 간주되어 무시됨
    • CSS에서는 white-space 스타일 속성값으로 웹 브라우저가 \n과 같은 화이트 스페이스를 어떻게 해석할지를 설정할 수 있음
  • 텍스트 정렬하기
  • 텍스트 표시 줄 수 조절하기
    • @tailwindcss/line-clamp라는 테일윈드 플러그인 사용
  • 텍스트 관련 컴포넌트 구현하기

3. CSS 상자 모델 이해하기

  • HTML 요소는 화면에 표시될 때 모두 상자처럼 보인다고 해서 상자모델(box model) 이라는 CSS 표준이 생김

3-1> 상자 모델이란?

  • 상자 모델은 HTML 태그가 웹 브라우저 화면에 모두 상자 모양으로 보이는 것을 모델링한 것으로, 이 모델에 따라 HTML 요소는 width와 height라는 스타일 속성을 가짐

3-2> width와 height 스타일 속성

3-3> Div 컴포넌트 구현하기

3-4> 컨테이너와 콘텐츠, 그리고 box-sizing 스타일 속성

  • HTML에서는 부모 요소, 자식 요소처럼 관계를 표현하지만, CSS에서는 부모 요소를 컨테이너 , 자식요소를 콘텐츠 라고 표현
  • CSS 관점에서 중요한 것은 HTML 요소의 관계가 아니라 HTML 요소의 렌더링이기 때문

3-5> 캐스케이딩(cascading) 알아보기

  • 'cascading'이라는 단어는 '위에서 아래로 물이 계단을 따라 흘러내린다'라는 의미로 해석할 수 있음
  • color 스타일 속성값을 명시적으로 설정하지 않으면 부모 요소에 설정한 color 속성값이 물이 흘러 내린듯이 적용됨

3-6> 뷰포트 알아보기

  • 뷰포트(viewport)는 웹 페이지에서 사용자가 볼 수 있는 영역
  • 뷰포트는 모바일, 테블릿, 데스크톱 등 웹브라우저가 동작하는 장치의 화면 크기가 각각 달라서 생긴 개념

3-7> 테일윈드CSS의 길이 관련 클래스

3-8> padding 스타일 속성

3-9> margin 스타일 속성

3-10> background-image 스타일 속성

  • <img>는 HTML 요소 중 유일하게 width와 height 속성이 있음. 이 속성은 이미지를 가로세로 화면 비율(aspect ratio)에 맞춰 표시함
  • img에 width와 height를 고정하더라도 실제 이미지가 로딩되면 높이가 줄어드는 현상이 발생. 이는 이미지가 왜곡되어 보이지 않도록 웹 브라우저가 화면 비율을 고려하여 height값을 계산했기 때문
  • img의 이런 특성은 이미지를 특정 높이로 고정하기 어렵게 하므로 디자이너들은 대부분 CSS의 background-image 스타일 속성을 선호함
  • Div 컴포넌트에 src 속성 추가

    import type {FC, DetailedHTMLProps, HTMLAttributes, PropsWithChildren} from 'react'
    import type {WidthHeight} from './WidthHeight'
    
    export type ReactDivProps = DetailedHTMLProps<
      HTMLAttributes<HTMLDivElement>,
      HTMLDivElement
    >
    export type DivProps = ReactDivProps &
      PropsWithChildren<WidthHeight> & {
        src?: string
      }
    
    export const Div: FC<DivProps> = ({
      width,
      height,
      style: _style,
      src,
      className: _className,
      ...props
    }) => {
      const style = {..._style, width, height, backgroundImage: src && `url(${src})`}
      const className = ['box-border', src && 'bg-gray-300', _className].join(' ')
      return <div {...props} className={className} style={style}></div>
    }

3-11> background-size 스타일 속성

3-12> border 스타일 속성

3-13> border-radius 스타일 속성

3-14> Avatar 컴포넌트 만들기

3-15> display 스타일 속성

  • inline 요소
    • CSS 레이아웃은 기본적으로 사람이 글을 쓰는 방식을 따름
    • 사람은 수평으로 글을 쓰다 더 이상 여분이 없으면 줄을 바꾼 뒤 글을 씀
    • 수평으로 쓰는 대표적인 HTML 요소로는 span이 있으며, span처럼 수평으로 배치되는 HTML 요소들을 inline 요소라고 함
    • inline 요소는 더 이상 수평으로 배치할 수 없을 때 줄을 바꾼 다음 왼쪽에서 오른쪽으로 배치됨
    • inline 요소는 width와 height 스타일 속성을 명시적으로 설정할 수 없음. 즉, 설정할 수는 있으나 반영되지 않음
  • block 요소
    • block 요소는 수직으로 배치되는 HTML 요소를 의미하여 div가 대표적
    • block 요소는 width와 height 스타일 속성값을 명시적으로 설정할 수 있고, 이 설정에 땨라 자신의 넓이와 높이를 설정할 수 있음
  • inline-block 요소
    • inline-block 요소는 inline과 block의 특성을 결합한 것
    • ineline이므로 수평으로 배치되지만, block이므로 width, height 스타일 속성값을 설정할 수 있음

3-16> visibility 스타일 속성

3-17> position과 left, top, right, bottom 스타일 속성

3-18> z-index 스타일 속성

3-19> Overlay 컴포넌트 만들기

4. 플렉스 레이아웃 이해하기

5. daisyui CSS 컴포넌트 이해하기

5-1> CSS 컴포넌트란?

  • HTML 요소의 스타일링을 쉽게하는 CSS 클래스를 제공하는 CSS 프레임워크(혹은 CSS 라이브러리)를 'CSS컴포넌트'라고 부름

5-2> 색상 테마

5-3> Button 컴포넌트 구현하기

  • 서브 컴포넌트 만들기
  • 'btn' 부분 생략하기
  • 버튼의 크기 설정하기

5-4> Icon 컴포넌트 구현하기

5-5> Input 컴포넌트 구현하기

  • 색상 설정하기
  • 테두리 설정하기
  • 크기 설정하기

5-6> 모달 컴포넌트 구현하기

함수 컴포넌트와 리액트 훅

  • 리액트 훅은 리액트 16.8 버전부터 새롭게 제공하는 기능

1 처음 만나는 리액트 훅

1-1> 리액트 훅이란?

  • 2019년 2월 16.8.0 버전을 내놓으면서 리액트 훅
  • 훅 함수는 반드시 함수 컴포넌트에서만 사용해야함

1-2> 리액트 훅의 탄생 배경

1-3> 리액트 훅 코드 패턴과 의존성 목록

  • 의존성 목록(dependency list)은 콜백 함수에서 사용되는 변수나 함수의 값이 일정하지 않고 수시로 변할 수 있을 때, 해당 변수나 함수를 아이템으로 갖는 배열을 의미함
  • 리액트 프레임워크는 의존성 목록에 있는 아이템 중 하나라도 변화가 있으면 콜백 함수를 새로 고침해 변한 값을 콜백 함수에 반영해줌

1-4> setInterval API로 시계 만들기

  • setInterval은 시스템 메모리 자원을 사용하므로, setInterval 콜백 함수가 동작하지 않게 할 때, 반드시 clearInterval 함수를 호출하여 메모리 누수(memory leak)가 생기지 않게 해야 함

1-5> useEffect 훅 사용하기

  • 의존성 목록에 있는 조건 중 어느 하나라도 충족되면 그때마다 콜백 함수를 다시 실행

1-6> useRef 훅 사용하기

1-7> useState 훅 사용하기

  • useState가 반환하는 setter는 현재 값이 변경되면 자동으로 해당 컴포넌트를 다시 렌더링하는 기능이 있음

1-8> 커스텀 훅이란?

  • 커스텀 훅(custom hook)
    • 여러 훅 함수를 조합해 마치 새로운 훅 함수가 있는 것처럼 만드는 것
    • 커스텀 훅은 리액트 훅 뿐만 아니라 기존에 제작한 커스텀 훅 함수를 사용해서 만들 수도 있음
    • 커스텀 훅 함수는 '훅'이라는 의미를 강조하고자 함수 이름에 'use'라는 접두어를 붙여서 만듬

1-9> 리액트 훅 함수의 특징

  1. 같은 리액트 훅을 여러 번 호출할 수 있다
  2. 함수 몸통이 아닌 몸통 안 복합 실행문의 {} 안에서 호출할 수 없다
  3. 비동기 함수를 콜백 함수로 사용할 수 없다
  • 리액트 훅을 사용한 개발이란, 몇 가지 적절한 훅 함수를 선택해 컴포넌트의 롲기을 개발하는 것. 그리고 될 수 있으면 커스텀 훅 함수로 만들어 좀 더 간결한 형태로 재사용할 수 있어야 함

2 useMemo와 useCallback 훅 이해하기

2-1> 리액트 훅의 기본 원리

  • 상태와 캐시
    • 프로그래밍 분야에서 상태(state)란 용어는 변수의 유효 범위와 무관하게 계속 유지(preserve)하는 값을 의미함
    • 상태는 불변 상태(immutable state)와 가변 상태(mutable state)로 나뉨
    • 함수 컴포넌트는 '함수'이므로 블록 범위라는 개념 때문에 상태를 가질 수 없음. 함수 컴포넌트가 상태를 가질 수 있는 방법은 상태를 담은 변수를 함수 몸통 바깥으로 꺼내어 블록 범위의 영향을 받지 않게 하는 것
    • 리액트 훅은 상태를 가질 수 없는 함수 컴포넌트로 하여금 마치 상태를 가진 것처럼 동작할 수 있게 함
    • 이런 개념을 이용하면 캐시(cache)를 전역 변수 형태로 만들어서 구현할 수 있음. 캐시는 데이터나 값을 미리 복사해 놓는 임시 저장소를 의미함. 캐시는 원본 데이터에 접근하는 시간이 오래 걸리거나 값을 다시 계산하는 시간을 절약하고 싶을 때 주로 사용함
  • 캐시 구현하기
  • 캐시 사용하기
  • 캐시와 의존성 목록
    • 리액트 프레임워크 내부에서 관리되는 캐시된 값은 어떤 상황이 일어나면 값을 갱신해 줘야함
    • 리액트 훅에서는 캐시를 갱신하게 하는 요소를 의존성(dependency)이라고 함
    • 의존성으로 구성된 배열을 의존성 목록(dependency list)라고 함
    • 리액트 프레임워크는 의존성 목록 중 어느 것 하나라도 조건이 충족되면 캐시된 값을 자동으로 갱신하고 해당 컴포넌트를 다시 렌더링하여 변경 사항을 반영해줌
  • 함수 컴포넌트와 리액트 훅을 사용하는 이유
    • 리액트는 컴포넌트의 속성값이 변할 때 항상 최신 값이 반영되도록 다시 렌더링을 해줌
    • 그런데 컴포넌트 내부 로직에서 컴포넌트가 다시 렌더링되는 때는 리액트가 탐지하기 어려움
    • 이 때문에 클래스 기반 컴포넌트는 다양한 메서드를 구현해서 렌더링 여부를 판다할 수 있게함
    • 반면에 함수 컴포넌트에 리액트 훅을 사용하면 리액트 프레임워크가 의존성 목록에서 변환값이 있는지만 판단하면 되므로 다시 렌더링해야 하는 때를 판단하기 쉬움

2-2> 데이터를 캐시하는 useMemo 훅

  • 'Memo'는 메모이제이션(memoization)의 줄임말
  • 메모이제이션은 과거에 계산한 값을 반복해서 사용할 때 과거에 계산한 값을 캐시해 두는 방법으로 전체 계산 속도를 높이는 코드 최적화 기법

2-3> 콜백 함수를 캐시하는 useCallback 훅

  • 고차 함수 사용하기
    • 고차 함수(higher-order function)는 다른 함수를 반환하는 함수를 의미
    • 리액트 개발에서 고차 함수는 콜백 함수에 어떤 정보를 추가로 전달하려고 할 때 주로 사용함
    • 리액트 프로그래밍에서 고차 함수를 구현하는 이유는 함수의 타입 불일치를 해결하기 위해서임

3 useState 훅 이해하기

3-1> 가변 상태를 캐시하는 useState 훅

  • useMemo 훅은 불변 상태를 캐시하지만, useState 훅은 가변 상태를 캐시함
  • useState 훅이 반환한 setter 함수는 리액트 프레임워크가 컴포넌트 내부의 상태 변화를 쉽게 감지할 수 있게 해줌. 즉, 리액트 프레임워크는 setter 함수가 호출되면 컴포넌트의 상태에 변화가 있는 것으로 판단하고 즉시 해당 컴포넌트를 다시 렌더링함

3-2> number 타입일 때 useState 훅 사용하기

3-3> 리액트 <number> 컴포넌트에 훅 사용하기

3-4> useToggle 커스텀 훅 만들기

3-5> 라디오 버튼 구현 방법

  • value 속성으로 라디오 버튼 선택 로직 구현하기
  • 고차 함수로 라이도 버튼 선택 로직 구현하기

3-6> HTML <form> 요소

  • 리액트와 같은 SPA 방식 프론트엔드 프레임워크를 사용할 때는 백엔드 웹 서버가 API 방식으로 동작하므로 굳이 <form> 요소와 action, method, encType 등의 속성을 설정할 필요가 없음. 다만 관습적으로 사용자 입력을 받는 부분을 <form> 요소로 구현
import type {FormEvent} from 'react'
// 중략
const onSubmit = (e: FormEvent<HTMLFormElement>) => {}
<form onSubmit={onSubmit}>
  <input type="submit" value="버튼_텍스트" />
</form>
  • onSubmit을 구현할 때 한 가지 주의할 점은 웹 브라우저는 onSubmit 이벤트가 발생하면 <form>이 있는 웹 페이지를 다시 렌더링한다는 것. 이 때문에 onSubmit을 구현할 때는 반드시 e.preventDefault()를 호출해 웹 페이지가 다시 렌더링되지 않도록 해야함

3-7> FormData 클래스

  • FormData는 자바스크립트 엔진이 기본으로 제공하는 클래스로서, 사용자가 입력한 데이터들을 웹 서버에 전송할 목적으로 사용함

3-8> 객체 타입 값일 때 useState 훅 사용하기

  • 깊은 복사(deep copy)와 얕은 복사(shallow copy), 그리고 의존성 목록

    • 복사 방식은 값의 타입에 따라 각기 다르게 적용됨
    • number, boolean 등 값의 메모릴 크기를 컴파일 타임 때 알 수 있는 타입은 항상 깊은 복사가 일어남
    • 반면, 객체, 배열 등 값의 메모리 크기를 런타임 때 알 수 있는 타입은 얕은 복사가 일어남
    • 한 가지 예외 상황은 string 타입 문자열인데, 타입스크립트에서 문자열은 항상 읽기 전용이므로 메모리 크기를 컴파일 타임 때 알 수 있음. 따라서 문자열은 깊은 복사가 일어남
    • 리액트는 내부적으로 form 상태에 변화가 생겼는지를 form === newForm 형태로 비교. 객체 타입의 복사는 항상 얇은 복사이므로 이 비굣값은 항상 true가 되는 문제 발생
    • 얇은 복사 문제는 Object.assign() 함수를 사용하면 깊은 복사가 일어나 form === newForm이 항상 false가 되어 웹 페이지를 다시 렌더링함
  • 객체에 적용하는 타입스크립트 전개 연산자 구문

    • Object.assign() 대신 전개 연산자로 편리하게 복사가능
  • 타입스크립트 객체 반환 구문

    • 타입스립트에서 객체를 반환하는 구문을 객체를 의미하는 중괄호 {}를 다시 소괄호로 감싼 ({}) 형태로 사용해야함
    setForm( form=>( {...form, name: e.target.value} ) )
  • ObjectState.tsx 파일 구현하기

3-9> 배열 타입 값일 때 useState 훅 사용하기

  • 배열에 적용하는 타입스크립트 전개 연산자 구문
  • ArrayState 컴포넌트 만들기

4 useEffect와 useLayoutEffect 훅 이해하기

4-1> 컴포넌트의 생명 주기란?

4-2> 클래스 컴포넌트에서 상태 구현하기

  • 컴포넌트 마운트
  • setState() 메서드
  • 클래스 컴포넌트의 언마운트

4-3> useLayoutEffect와 useEffect 훅 알아보기

  • 두 훅은 사용법이 같으며 콜백 함수는 훅일 실행될 때 처음 한번은 실행됨
  • 클래스 컴포넌트의 componentDidMount() 메서드를 구혀한 것과 사실상 같은 효과를 보임
  • 두 훅인 componentDidMount()와 다른 점은 한 번 실행되는 componentDidMount()와 달리, 두 훅은 의존성 목록이 변경될 때마다 콜백 함수를 계속 실행한다는 점
  • useLayoutEffect와 useEffect 훅의 차이점

    • useLayoutEffect 훅
      * 동기(synchronous)
      • 콜백함수가 끝날때까지 프레임워크가 기다림
    • useEffect 훅
      • 비동기 (asynchronous)
      • 콜백함수의 종료를 기다리지 않음
    • 리액트 공식 문서에는 될 수 있으면 useEffect 훅을 사용하고 useEffect 훅으로 구현이 안될 때만 useLayoutEffect 훅을 사용하라고 권함
  • useInterval 커스텀 훅 고찰해 보기

  • useEventListener 커스텀 훅 만들기

    • addEventListener() 메서드를 호출하면 반드시 removeEventListener() 메서드를 호출해 주어야 메모리 누수가 발생하지 않음
  • useWindowResize 커스텀 훅 만들기

    • 웹 분야에서 반응형 디자인이란 웹 브라우저의 크기에 따라 웹 페이지를 구성하는 HTML 요소들의 크기와 위치를 변하게 해서 최상의 사용자 경험을 주는 설계를 의미
    • 데스크톱에서는 모바일이나 테블릿과 달리 사용자가 웹 브라우저의 크기를 마우스로 바꿀 수 있음. 이 때문에 데스크톱을 대상으로 할 때는 웹 페이지의 크기가 변경될 때마다 이를 탐지해서 그에 맞는 형태로 HTML 요소들의 크기와 위치를 바꿔 줘야함
  • fetch() 함수와 Promise 클래스 고찰해 보기

    • fetch() 함수와 Promise 클래스는 자바스크립트 엔진에서 기본으로 제공하는 API
    • fetch()는 HTTP 프로토콜의 GET, POST, PUT, DELETE와 같은 HTTP 메서드를 프로그래밍으로 쉽게 사용하게 해줌
    fetch('https://randomuser.me/api')
        .then(res => res.jon())
        .then((data: unknown) => console.log(data))
        .catch((err:Error) => console.log(err.message))
        .finally(() => console.log("always called"))
  • API 서버에서 가져온 사용자 정보 화면에 표시하기

5 useRef와 useImperativeHandle 훅 이해하기

5-1> ref 속성이란?

5-2> useRef 훅 알아보기

  • 의 클릭 메서드 호출하기
  • FileList 클래스와 Array.from() 함수
  • FileReader 클래스로 File 타입 객체 읽기
  • imageFileReaderP 유틸리티 함수 만들기
  • FileDrop 컴포넌트 만들기
  • useState 호출 없이 의 value 속성값 얻기

5-3> forwardRef 함수 이해하기

  • forwardRef 함수가 필요한 이유 알기
  • forwardRef 함수의 타입

5-4> useImperativeHandle 훅이란?

  • useImpertativeHandle 훅의 동작 원리
  • useImperativeHandle 훅의 타입
  • ValidatableInput 컴포넌트 만들기

6 useContext 훅 이해하기

1> 컨텍스트란?
2> createContext 함수 탐구
3> 테일윈드CSS의 중단점 접두사 이해하기
4> 반응형 컨텍스트로 만들기

  • 컨텍스트 객체가 제공하는 Provider 컴포넌트
  • ResponsiveProvider 컴포넌트 만들기
    5> useContext 훅 알아보기

상태 관리와 리덕스 패키지

  • 리덕스는 가장 널리 사용되는 리액트 프레임워크용 앱 수준 상태 관리 패키지

1 리덕스 기본 개념 이해하기

1-1> 리덕스와 리덕스 관련 필수 패키지

1-2> 앱 수준 상태 알아보기

  • 앱을 구성하는 모든 컴포넌트가 함께 공유할 수 있는 상태를 앱 수준 상태(app-level-states) 라고함. 줄여서 '앱 상태'라고 함
  • Provider 컴포넌트와 store 속성
    • 리액트 컨텍스트에 기반을 둔 라이브러리
    • 리덕스 기능을 사용하려면 리액트 컨텍스트의 Provider 컴포넌트가 최상위로 동작해야 함
  • 리덕스 저장소와 리듀서, 액션 알아보기
    • 리덕스 저장소(redux store) 는 AppState 타입 데이터를 저장하는 공간
    • 리덕스에 리듀서(reducer) 는 현재 상태와 액션이라는 2가지 매개변수로 새로운 상태를 만들어서 반환
  • 스토어 객체 관리 함수
    • RTK 패키지는 리듀서에서 반환한 새로운 상태를 스토어(store) 라는 객체로 정리해 관리하는 configureStore 함수를 제공함
  • 기본 앱 파일 분리하기

1-3> useSelector 훅 사용하기

  • 리덕스 액션 알아보기
  • 리덕스 리듀서 알아보기
    • '첫 번째 매개변수에 담긴 과거 상탯값(preState)을 바탕으로 새로운 상탯값(newState)을 반환한다'라는 리듀서의 함수의 목적
    • 리듀서(reducer)라는 이름에는 prevState와 action 두 객체를 결합하여 1개의 newState로 줄이는(reduce) 용도라는 의미를 내포하고 있음

1-4> useDispatch 훅 사용하기

  • dispatch() 함수를 사용하여 리덕스 저장소에 저장된 AppState 객체의 멤버 전부나 일부를 변경할 수 있음
  • dispatch 함수와 리듀서 간의 관계 이해하기
    • dispatch(액션) --> 리듀서 --> 리덕스 저장소
  • 시계 완성하기

1-5> useReducer 훅 사용하기

  • 리덕스와 리듀서는 사실상 똑같은 기능을 수행함
  • useReducer 훅은 ReduxProvider와 같은 컨텍스트 없이 사용함
  • 리덕스의 상태는 앱의 모든 컴포넌트에서 접근할 수 있지만(전역 상태), useReducer 훅의 상태는 다른 훅 함수들처럼 useReducer 훅을 호출한 컴포넌트 안에서만 유효(지역 상태)하다는 차이가 있음
  • src/copy 디렉터리에 리덕스 관련 파일 생성하기

2 리듀서 활용하기

1> 리듀서 합치기
2> 앱 상태를 구성하는 멤버 상태 구현하기
3> 시계 만들기
4> 카운터 만들기

  • '@이름/' 접두사와 payload라는 변수 이름을 사용하는 이유 알기
  • 리듀서는 순수 함수여야 한다
    5> 사용자 정보 변경 기능 만들기
    6> 사용자 카드 만들기

3 리덕스 미들웨어 이해하기

1> 리덕스 미들웨어란?
2> 로거 미들웨어 만들기

  • 미들웨어 설정하기
  • 미들웨어 테스트하기
  • 리덕스 로거 패키지 사용하기
    3> 썽크 미들웨어 알아보기
  • 로딩 UI 구현하기
  • 오류 메시지 구현하기
    4> 사용자 정보 변경 기능 개선하기

4 트렐로 따라 만들기

1> 칸반 보드란?

  • react-dnd 패키지 설치하기
  • react-beautiful-dnd 패키지 설치하기
  • 앱 상태를 구성하는 멤버 상태 만들기
  • src/pages에 테스트용 컴포넌트 만들기
    2> CreateListForm 컴포넌트 구현하기
  • 배열 대신 ids와 entities로 상태 구현하기
  • 타입스크립트의 Record 타입
    3> 공통으로 사용하는 타입 구현하기
    4> listidOrders 멤버 상태 구현하기
    5> listEntities 멤버 상태 구현하기
    6> BoardList 컴포넌트 구현하기
    7> 리덕스 기능을 커스텀 훅으로 만들기
    8> ListCard 컴포넌트 구현하기
    9> CardEntities 멤버 상태 구현하기
    10> listidCarddidOrders 멤버 상태 구현하기
    11> useCards 커스텀 훅 만들기
    12> react-dnd의 useDrop 훅 알아보기
    13> react-dnd의 useDrag 훅 알아보기
    14> ListDraggable 컴포넌트 구현하기
    15> react-beautiful-dnd 패키지 이해하기
    16> CardDraggable 컴포넌트 구현하기
    17> CardDroppable 컴포넌트 구현하기
    18> 배열 관련 유틸리티 함수 구현하기
    19> OnDragEnd 콜백 함수 구현하기

from handling library

  • formik
  • react-hook-form

Reference

profile
#의식의흐름 #순간순간 #생각의스냅샷

0개의 댓글