재사용되지 않는 함수이고, 단 한번만 실행되고 끝난다면 즉시 실행 함수(IIFE)의 사용을 검토해보자
부수효과가 없는 함수 -> 순수함수, 부수효과가 존재하는 함수 -> 비순수 함수
부수효과는 어떻게 보면 피할 수 없는 요소 -> API 호출, console.log, useEffect 등
함수는 하나의 일을, 그 하나만 잘하면 된다.
가능한 한 함수 이름은 간결하고 이해하기 쉽게 붙이는 것이 좋다.
클래스
클래스는 객체지향 언어를 사용하던 다른 프로그래머가 좀 더 자바스크립트에 접근하기 쉽게 만들어주는, Syntatic Sugar이다.
클로저
클로저는 해당 함수가 선언된 어휘적 환경을 기억하기 때문에 동작한다.
클로저에 꼭 필요한 작업만 남겨두지 않는다면 메모리를 불필요하게 잡아먹는 결과를 야기할 수 있다.
부수효과가 없고 순수해야 한다는 목적을 달성하기 위해 적극적으로 사용되는 개념
이벤트 루프와 비동기 통신
하나의 프로세스에서는 여러 개의 스레드를 만들 수 있다.
자바스크립트 창시자: 브랜던 아이크(Brendan Eich)
자바스크립트의 모든 코드는 '동기식'으로 한 번에 하나씩 순차적으로 처리된다.
이벤트 루프
콜 스택
태스크 큐
마이크로 태스크 큐
리액트에서 자주 사용하는 자바스크립트 문법
바벨은 자바스크립트의 최신 문법을 다양한 브라우저에서도 일관적으로 지원할 수 있도록 코드를 트랜스파일한다.
구조 분해 할당
객체 초기자
즉시 실행 함수를 사용하여 삼항 연산자를 사용하지 않고 JSX에서 조건부 렌더링 가능
선택이 아닌 필수, 타입스크립트
타입스크립트는 타입 체크를 정적으로 런타임이 아닌 빌드(트랜스파일) 타임에 수행할 수 있게 한다.
any는 정말로 예외적인 경우에만 사용
타입 가드를 적극 활용하자
instanceof와 typeof
in -> 어떤 객체에 키가 존재하는지 확인하는 용도로 사용
제네릭 -> 제네릭을 두개 이상 사용할 경우 T, U 등으로 표현하는 것보다 적절히 네이밍하는 것이 좋다.
인덱스 시그니처
타입스크립트 전환 가이드
[2장] 리액트 핵심 요소 깊게 살펴보기
JSX란?
가상 DOM과 리액트 파이버
DOM과 브라우저 렌더링 과정
재조정(reconciliation)
리액트 파이버
리액트 파이버는 리액트에서 관리하는 평범한 자바스크립트 객체로, 가상 DOM과 렌더링 과정 최적화를 가능하게 해준다.
리액트 웹 애플리케이션에서 발생하는 애니메이션, 레이아웃, 그리고 사용자 인터랙션에 올바른 결과물을 만드는 반응성 문제를 해결하는 것이 목표
모든 과정이 비동기로 일어난다. -> 과거에는 스택으로 이루어졌지만, 동기적으로 이루어지다보니 리액트의 비효율성 초래
파이버의 작업 단계
파이버는 컴포넌트가 최초로 마운트되는 시점에 생성되어 이후에는 가급적이면 재사용된다. (가급적 새로운 파이버를 생성하지 않는다.)
리액트 파이버의 주요 속성
리액트 파이버 트리
리액트 파이버는 리액트 네이티브와 같은 브라우저가 아닌 환경에서도 사용할 수 있기 때문에 파이버와 가상 DOM은 동일한 개념이 아니다.
가상 DOM과 리액트의 핵심은 브라우저의 DOM을 더욱 빠르게 그리고 반영하는 것이 아니라 바로 값으로 UI를 표현하는 것이다.
화면에 표시되는 UI를 자바스크립트의 문자열, 배열 등과 마찬가지로 값으로 관리하고 이러한 흐름을 효율적으로 관리하기 위한 메커니즘이 바로 리액트의 핵심이다.
클래스 컴포넌트와 함수 컴포넌트
클래스 컴포넌트
함수 컴포넌트
렌더링은 어떻게 일어나는가?
리액트에서의 렌더링이란 리액트 애플리케이션 트리 안에 있는 모든 컴포넌트들이 현재 자신들이 가지고 있는 props와 state의 값을 기반으로 어떻게 UI를 구성하고 이를 바탕으로 어떤 DOM 결과를 브라우저에 제공할 것인지 계산하는 일련의 과정을 의미한다.
리액트의 렌더링이 일어나는 이유 [p.173]
useState 등으로 관리되지 않는 단순한 변수(let, const)는 제아무리 변경된다 하더라도 리렌더링을 발생시키지 않아 변경된 값을 렌더링된 DOM에서 확인할 수 없다.
일반적으로 렌더링 결과물은 JSX 문법으로 구성돼 있고, 이것이 자바스크립트로 컴파일되면서 React.createElement()를 호출하는 구문으로 변환된다.
리액트의 렌더링
렌더 단계와 커밋 단계라는 총 두 단계로 분리되어 실행된다.
렌더 단계
컴포넌트를 렌더링하고 변경 사항을 계산하는 모든 작업
변경이 필요한 컴포넌트를 체크하는 단계
여기서 비교하는 것은 크게 세 가지로, type, props, key이다.
커밋 단계
리액트의 렌더링이 일어난다고 해서 무조건 DOM 업데이트가 일어나는 것은 아니다.
-> 렌더링을 수행했으나 커밋 단계까지 갈 필요가 없다면, 즉 변경 사항을 계산했는데 아무런 변경 사항이 감지되지 않는다면 이 커밋 단계는 생략될 수 있다.
의도된 우선순위로 컴포넌트를 렌더링해 최적화할 수 있는 비동기 렌더링, 이른바 동시성 렌더링이 리액트 18에서 도입되었다.
-> 이를 통해 브라우저의 동기 작업을 차단하지 않고 백그라운드에서 새로운 리액트 트리를 준비할 수도 있으므로 사용자는 더욱 매끄러운 사용자 경험을 누릴 수 있다.
컴포넌트와 함수의 무거운 연산을 기억해 두는 메모이제이션
주장 1: 섣부른 최적화는 독이다, 꼭 필요한 곳에만 메모이제이션을 추가하자
주장 2: 렌더링 과정의 비용은 비싸다, 모조리 메모이제이션해 버리자.
항상 무엇이 더 저렴한지를 매번 계산하기 보다 무조건 메모이제이션하는 방법을 고민해보자.
메모이제이션은 하지 않는 것보다 메모이제이션 했을 때 더 많은 이점을 누릴 수 있다.
저자 입장
[3장] 리액트 훅 깊게 살펴보기
리액트의 모든 훅 파헤치기
useState
리액트의 렌더링은 함수 컴포넌트에서 반환한 결과물인 return 값을 비교해 실행되기 때문에 state가 아닌 변수가 변경되어도 렌더링이 일어나지 않는다.
매번 렌더링이 발생될 때마다 함수는 다시 새롭게 실행되고, 새롭게 실행되는 함수에서 state는 매번 선언 시 값으로 초기화된다.
useState는 클로저를 이용했다.
useState에 변수 대신 함수를 넘기는 것을 게으른 초기화(lazy initialization)라고 한다.
useEffect
useEffect는 애플리케이션 내 컴포넌트의 여러 값들을 활용해 동기적으로 부수 효과를 만드는 메커니즘이다.
useEffect는 자바스크립트의 proxy나 데이터 바인딩, 옵저버 같은 특별한 기능을 통해 값의 변화를 관찰하는 것이 아니고 렌더링할 때마다 의존성에 있는 값을 보면서 이 의존성의 값이 이전과 다른 게 하나라도 있으면 부수 효과를 실행하는 평범한 함수이다.
useEffect 내에서 반환되는 함수를 클린업 함수라고 한다.
의존성 배열에 빈 배열을 둔다면 리액트가 이 useEffect는 비교할 의존성이 없다고 판단해 최초 렌더링 직후에 실행된 다음부터는 더 이상 실행되지 않는다.
의존성 배열에 아무런 값도 넘겨주지 않는다면 이때는 의존성을 비교할 필요 없이 렌더링할 때마다 실행이 필요하다고 판단해 렌더링이 발생할 때마다 실행된다.
의존성 배열이 없는 useEffect가 매 렌더링마다 실행된다면 그냥 useEffect 없이 써도 되는게 아닐까?
eslint-disable-line react-hooks/exhaustive-deps 주석은 최대한 자제하라.
익명 함수가 아닌 적절한 이름을 사용한 기명 함수로 바꾸는 것이 좋다.
거대한 useEffect를 만들지 마라
useEffect 내에서 사용할 부수 효과라면 내부에서 만들어서 정의해서 사용하는 편이 훨씬 도움이 된다.