diff --git "a/week-01/\352\271\200\354\244\200\354\227\264.md" "b/week-01/\352\271\200\354\244\200\354\227\264.md" new file mode 100644 index 0000000..d5a4c50 --- /dev/null +++ "b/week-01/\352\271\200\354\244\200\354\227\264.md" @@ -0,0 +1,1119 @@ +# 모던 리액트 Deep Dive | 01장. 리액트 개발을 위해 꼭 알아야 할 자바스크립트 + +> 함수형 컴포넌트, 클로저, 이벤트 루프, 타입스크립트까지 +> 리액트를 제대로 이해하기 위해 필요한 자바스크립트 핵심 개념 정리 + +--- + +# 1.1 자바스크립트의 동등 비교 + +리액트는 단순히 state가 바뀌었다고 무조건 렌더링하지 않는다. +이전 값과 현재 값을 비교해 “값이 변경되었다”고 판단될 때 렌더링을 수행한다. + +특히: +- props 비교 +- React.memo +- useEffect dependency array +- useMemo / useCallback + +등에서 모두 동등 비교가 사용된다. + +리액트는 기본적으로 객체를 깊게 비교하지 않고 **얕은 비교(shallow compare)** 를 사용한다. + +즉: +- 원시값 → 값 비교 +- 객체/배열 → 참조값 비교 + +를 수행한다. + +```js +const a = { x: 1 } +const b = { x: 1 } + +console.log(a === b) // false +``` + +내용은 같지만 메모리 주소가 다르기 때문에 false다. + +따라서 리액트에서는: +- 객체를 직접 수정하지 않고 +- 새로운 객체를 생성해 상태를 변경하는 + +불변성 유지가 매우 중요하다. + +--- + +# 1.1.1 자바스크립트의 데이터 타입 + +## 원시 타입 (Primitive Type) + +```txt +boolean +null +undefined +number +string +symbol +bigint +``` + +특징: +- 객체가 아닌 모든 타입 +- immutable(불변) +- 값 자체 저장 +- 메서드를 직접 가지지 않음 + +원시 타입은 메모리에 값 자체가 저장된다. + +```js +let a = 1 +let b = a + +b = 2 + +console.log(a) // 1 +``` + +복사 시 값 자체를 복사하기 때문에 원본에 영향이 없다. + +--- + +## undefined + +- 선언 후 값을 할당하지 않은 변수 +- 값이 주어지지 않은 인수에 자동 할당되는 값 + +```js +let a +console.log(a) // undefined +``` + +JS 엔진이 자동으로 넣는 값이라는 특징이 있다. + +--- + +## null + +- 아직 값이 없거나 비어있음을 표현 +- 개발자가 의도적으로 “비어있음”을 나타냄 + +```js +const user = null +``` + +### 특징 + +```js +typeof null === 'object' // true +``` + +JS 초기 설계 실수로 인해 object 반환 + +현재는 웹 호환성 문제 때문에 수정되지 못하고 있다. + +--- + +## undefined vs null + +| 값 | 의미 | +|---|---| +| undefined | 선언됐지만 값이 없음 | +| null | 의도적으로 비워둠 | + +--- + +## falsy 값 + +조건문에서 false처럼 동작하는 값 + +```txt +false +0 +NaN +'' +null +undefined +``` + +--- + +## truthy 값 + +조건문에서 true처럼 동작하는 값 + +주의: +- 빈 배열 `[]` +- 빈 객체 `{}` + +도 truthy다. + +```js +Boolean([]) // true +Boolean({}) // true +``` + +--- + +## String + +### template literal + +- 백틱(``) 사용 +- 줄바꿈 가능 +- 표현식 삽입 가능 + +```js +const name = 'kim' + +console.log(`hello ${name}`) +``` + +특징: +- 원시 타입 +- 변경 불가능(immutable) + +--- + +## Symbol + +- 중복되지 않는 고유 값 생성 +- 객체의 고유 key 생성 시 자주 사용 + +```js +const key = Symbol('id') +``` + +--- + +# 객체 타입 (Object Type) + +원시 타입 제외 모든 것 + +포함: +- 배열 +- 함수 +- 정규식 +- 클래스 + +특징: +- 참조 타입(reference type) +- 값을 복사할 때 참조 전달 + +```js +const a = { x: 1 } +const b = a + +b.x = 2 + +console.log(a.x) // 2 +``` + +같은 객체를 참조하기 때문에 원본도 변경된다. + +--- + +# 1.1.2 값을 저장하는 방식의 차이 + +## 원시 타입 + +- 값 자체 저장 +- immutable +- 복사 시 값 복사 + +--- + +## 객체 타입 + +- 참조 저장 +- mutable +- 복사 시 참조 공유 + +즉 객체는 내부 값이 같아도: + +```js +{} === {} // false +``` + +가 된다. + +리액트에서 얕은 비교를 이해하려면 반드시 알아야 하는 개념이다. + +--- + +# 1.2 함수 + +자바스크립트에서 함수는 단순 코드 묶음이 아니다. + +함수는: +- 변수에 저장 가능 +- 함수 인자로 전달 가능 +- 함수 반환 가능 + +즉 일급 객체(first-class citizen)다. + +--- + +# 1.2.2 함수를 정의하는 4가지 방법 + +## 함수 선언문 + +```js +function add(a, b) { + return a + b +} +``` + +특징: +- 가장 일반적인 방식 +- statement(문) +- 함수 호이스팅 발생 + +```js +hello() + +function hello() { + console.log('hello') +} +``` + +위 코드가 가능한 이유는 함수 선언이 실행 전에 메모리에 등록되기 때문이다. + +--- + +## 함수 표현식 + +```js +const add = function (a, b) { + return a + b +} +``` + +함수를 변수처럼 다루는 방식. + +주의: + +```js +hello() + +const hello = function () {} +``` + +위 코드는 에러 발생. + +이유: +- 변수는 undefined만 먼저 올라가고 +- 함수 할당은 런타임에 수행되기 때문. + +--- + +## Function 생성자 + +```js +const add = new Function('a', 'b', 'return a + b') +``` + +특징: +- 문자열 기반 생성 +- 클로저 생성 안 됨 +- 거의 사용하지 않음 + +보안/성능 문제 때문에 권장되지 않는다. + +--- + +## 화살표 함수 + +```js +const add = (a, b) => a + b +``` + +특징: +- constructor 사용 불가 +- this 바인딩 방식 다름 + +일반 함수: +- 호출 방식에 따라 this 결정 + +화살표 함수: +- 상위 스코프의 this 사용(lexical this) + +--- + +# 1.2.3 다양한 함수 살펴보기 + +## 즉시 실행 함수 (IIFE) + +```js +(function (a, b) { + return a + b +})(10, 24) +``` + +특징: +- 선언 즉시 실행 +- 재호출 불가 +- 독립 스코프 생성 + +과거 var 중심 환경에서: +- 전역 변수 오염 방지 +목적으로 자주 사용했다. + +--- + +## 고차 함수 + +함수를: +- 인수로 받거나 +- 함수를 반환하는 함수 + +```js +const doubledArray = [1, 2, 3].map((item) => item * 2) +``` + +대표적인 고차 함수: +- map +- filter +- reduce + +리액트에서는: +- HOC +- custom hook +- render props + +등이 모두 고차 함수 기반이다. + +--- + +# 1.2.4 함수를 만들 때 주의사항 + +## 함수의 부수 효과를 최대한 억제하라 + +### 부수 효과(side effect) + +함수 외부 상태를 변경하는 것 + +```js +let count = 0 + +function increase() { + count++ +} +``` + +--- + +## 순수 함수 + +특징: +- 동일 입력 → 동일 출력 +- 외부 상태 변경 없음 +- 예측 가능 + +```js +function add(a, b) { + return a + b +} +``` + +--- + +## 리액트에서 중요 포인트 + +리액트는 예측 가능한 UI를 중요하게 생각한다. + +따라서: +- side effect 최소화 +- useEffect 남용 방지 +- 함수 역할 분리 + +가 중요하다. + +--- + +## 함수를 가능한 작게 만들어라 + +함수가 커질수록: +- 추적 어려움 +- 디버깅 어려움 +- 재사용성 감소 + +좋은 함수는: +- 하나의 책임만 가진다. + +--- + +## 이해 가능한 이름 사용 + +```js +useEffect(function apiRequest() { + // ... +}, []) +``` + +이름 있는 함수는: +- 디버깅 +- 스택 트레이스 +- 가독성 + +측면에서 유리하다. + +--- + +# 1.3 클래스 + +## 클래스란? + +객체 생성을 위한 템플릿. + +```js +class Car { + constructor(name) { + this.name = name + } +} +``` + +--- + +## constructor + +생성자 메서드. + +객체 생성 시 자동 호출된다. + +```js +const car = new Car('BMW') +``` + +동작 순서: +1. 객체 생성 +2. constructor 실행 +3. this 바인딩 + +--- + +## 인스턴스 메서드 + +```js +class Car { + drive() {} +} +``` + +실제로는 prototype에 저장된다. + +```js +Car.prototype.drive +``` + +형태로 존재. + +--- + +## 프로토타입 체이닝 + +JS 객체는: +- 자기 자신 +- prototype +- Object + +순으로 탐색한다. + +이 과정을 prototype chaining이라 한다. + +--- + +## 정적 메서드(static) + +```js +class Car { + static hello() { + console.log('hello') + } +} +``` + +사용: + +```js +Car.hello() +``` + +특징: +- 인스턴스 생성 없이 사용 가능 +- 유틸 함수에 자주 사용 + +대표 예: +- Math.max +- Array.isArray + +--- + +# 1.4 클로저 + +함수형 컴포넌트 핵심 개념. + +| 컴포넌트 | 핵심 개념 | +|---|---| +| 클래스형 컴포넌트 | class, prototype, this | +| 함수형 컴포넌트 | closure | + +React Hook은 대부분 클로저 기반으로 동작한다. + +--- + +# 1.4.1 클로저 정의 + +> 함수와 함수가 선언된 렉시컬 스코프의 조합 + +쉽게 말하면: + +> 함수가 자신이 생성된 환경을 기억하는 것 + +--- + +# 1.4.2 변수의 유효 범위, 스코프 + +## 전역 스코프 + +어디서든 접근 가능 + +브라우저: +```js +window +``` + +Node.js: +```js +global +``` + +--- + +## 함수 스코프 + +JS는 기본적으로 함수 레벨 스코프. + +```js +if (true) { + var global = 'global scope' +} + +console.log(global) +``` + +가능한 이유: +- var는 함수 스코프이기 때문. + +--- + +# 1.4.3 클로저 활용 + +```js +function outerFunction() { + var x = 'hello' + + function innerFunction() { + console.log(x) + } + + return innerFunction +} + +const innerFunction = outerFunction() +innerFunction() +``` + +출력: + +```txt +hello +``` + +innerFunction이 outerFunction의 스코프를 기억하기 때문이다. + +--- + +## 리액트에서의 클로저 + +```js +function Component() { + const [state, setState] = useState() + + function handleClick() { + setState((prev) => prev + 1) + } +} +``` + +setState가 최신 값을 기억 가능한 이유: +- 클로저로 state 환경을 기억하기 때문. + +--- + +# 1.4.4 클로저 주의점 + +## 잘못된 코드 + +```js +for (var i = 0; i < 5; i++) { + setTimeout(function () { + console.log(i) + }, i * 1000) +} +``` + +출력: + +```txt +5 +5 +5 +5 +5 +``` + +원인: +- var는 함수 스코프 +- 하나의 i를 공유 + +--- + +## 해결 1: let 사용 + +```js +for (let i = 0; i < 5; i++) { + setTimeout(function () { + console.log(i) + }, i * 1000) +} +``` + +let은 block scope라 반복마다 새로운 i 생성. + +--- + +## 해결 2: IIFE 사용 + +```js +for (var i = 0; i < 5; i++) { + setTimeout( + (function (sec) { + return function () { + console.log(sec) + } + })(i), + i * 1000, + ) +} +``` + +각 반복마다 독립 스코프 생성 가능. + +--- + +## 클로저 사용 시 주의 + +클로저는: +- 외부 환경 기억 필요 +- 메모리 유지 비용 발생 + +불필요한 클로저 남발은: +- 메모리 누수 +- 성능 저하 + +원인이 될 수 있다. + +--- + +# 1.5 이벤트 루프와 비동기 통신 + +JS는 싱글 스레드 기반. + +즉: +- 한 번에 하나의 작업만 수행 가능 + +--- + +## 동기(synchronous) + +```txt +작업 A 완료 → 작업 B 실행 +``` + +특징: +- 직관적 +- 병렬 처리 어려움 + +--- + +## 비동기(asynchronous) + +```txt +작업 A 요청 +→ 기다리지 않음 +→ 작업 B 실행 +``` + +대표 예: +- fetch +- setTimeout +- 이벤트 핸들러 + +--- + +# 1.5.1 싱글 스레드 JS + +JS가 싱글 스레드를 선택한 이유: +- DOM 조작 안정성 확보 + +멀티 스레드 환경에서 동시에 DOM 수정 시: +- race condition +- 동시성 문제 + +발생 가능. + +--- + +## Run-to-completion + +하나의 작업이 끝날 때까지: +- 다른 JS 실행 불가 + +즉: +- 긴 작업은 UI 멈춤 현상 유발 가능. + +--- + +# 1.5.2 이벤트 루프 + +## 콜 스택(Call Stack) + +실행 중인 함수 저장. + +--- + +## 태스크 큐(Task Queue) + +비동기 콜백 저장. + +예: +- setTimeout +- 이벤트 핸들러 + +--- + +## 이벤트 루프(Event Loop) + +역할: +1. 콜 스택 확인 +2. 비었는지 검사 +3. Task Queue 작업 실행 + +--- + +## 비동기 작업은 누가 처리하나? + +브라우저(Web API)가 처리. + +즉: +- JS 엔진이 직접 비동기 작업 수행하는 게 아니다. + +--- + +# 1.5.3 마이크로태스크 큐 + +대표: +- Promise +- queueMicrotask + +특징: +- 일반 Task Queue보다 우선순위 높음 + +```js +Promise.resolve().then(() => console.log('micro')) + +setTimeout(() => console.log('task')) +``` + +출력: + +```txt +micro +task +``` + +--- + +# 1.6 리액트에서 자주 사용하는 JS 문법 + +## 구조 분해 할당 + +### 배열 구조 분해 + +```js +const [count, setCount] = useState(0) +``` + +순서 기반. + +--- + +### 객체 구조 분해 + +```js +const { name, age } = user +``` + +이름 기반. + +--- + +## 전개 구문(spread) + +### 배열 + +```js +const arr2 = [...arr1] +``` + +새 배열 생성. + +--- + +### 객체 + +```js +const obj = { + ...prev, + age: 20, +} +``` + +불변성 유지에 매우 중요. + +--- + +## 객체 초기자 + +```js +const a = 1 +const b = 2 + +const obj = { a, b } +``` + +간결하게 객체 생성 가능. + +--- + +## Array 메서드 + +### map + +```js +arr.map((v) => v * 2) +``` + +새 배열 반환. + +--- + +### filter + +```js +arr.filter((v) => v > 3) +``` + +조건 만족 요소 반환. + +--- + +### reduce + +```js +arr.reduce((acc, cur) => acc + cur, 0) +``` + +누적 계산. + +--- + +### forEach + +주의: +- break 불가 +- 중간 종료 불가 + +성능상 주의 필요. + +--- + +# 1.7 타입스크립트 + +## 타입스크립트란? + +> TypeScript is JavaScript with syntax for types. + +특징: +- JS 슈퍼셋 +- 정적 타입 검사 제공 +- 빌드 타임 에러 검출 가능 + +--- + +# any 대신 unknown 사용 + +## any + +문제: +- 타입 안정성 포기 + +--- + +## unknown + +특징: +- narrowing 필요 + +```ts +if (typeof value === 'string') { +} +``` + +--- + +# 타입 가드 + +## typeof + +```ts +typeof value === 'string' +``` + +--- + +## instanceof + +```ts +value instanceof Error +``` + +--- + +## in + +```ts +if ('age' in person) +``` + +--- + +# 제네릭(Generic) + +```ts +function identity(value: T): T { + return value +} +``` + +장점: +- 재사용성 +- 타입 안정성 + +동시 확보. + +--- + +# 인덱스 시그니처 + +```ts +type Hello = { + [key: string]: string +} +``` + +주의: +- 존재하지 않는 키 접근 가능 + +--- + +# Object.keys 문제 + +```ts +Object.keys(hello).map((key) => { + hello[key] +}) +``` + +에러 원인: +- Object.keys → string[] + +--- + +# 해결 방법 + +## 타입 단언 + +```ts +Object.keys(hello) as Array +``` + +--- + +## 타입 가드 함수 + +```ts +function keysOf( + obj: T +): Array { + return Object.keys(obj) as Array +} +``` + +--- + +# 1.7.3 타입스크립트 전환 가이드 + +## tsconfig.json + +```json +{ + "compilerOptions": { + "outDir": "./dist", + "allowJs": true, + "target": "es5" + } +} +``` + +--- + +## JSDoc + @ts-check + +```js +//@ts-check +``` + +JS에서도 타입 체크 가능. + +--- + +## @types 설치 + +```bash +npm install @types/react +``` + +DefinitelyTyped 기반 타입 제공. + +--- + +# 점진적 전환 추천 순서 + +1. 상수 +2. 유틸 함수 +3. 의존성 적은 파일 +4. 컴포넌트 + +---