문서를 읽게 된 동기
회사에서 Vue2 인 프로젝트를 React 로 마이그레이션 하는 작업을 진행중입니다. 코드의 퀄리티를 높이고, 팀원 분들의 PR을 더 수준높게 봐드리고 싶어서 React 공식문서를 읽게 되었습니다. 기존 vue 문법과 어떤 점이 다른 지를 비교하면서 문서를 보려고 합니다.
React 문서 소개
https://ko.react.dev/
react는 한글판 문서가 따로 존재합니다. 문서가 자세해서 새로 배우시는 분들도 학습하기 좋습니다.
학습하기
탭에서는 기본적인 개념부터 심화과정까지 react 를 다루는 방법을 소개하고 있습니다. 예제가 자세하고, 각 섹션 하단에 직접해볼 수 있는 챌린지가 있어 직접 코드를 짜보면서 학습할 수 있어 좋았습니다.
빠르게 시작하기
React로 사고하기
- state는 앱이 기억해야 하는, 변경할 수 있는 데이터의 최소 집합이다.
- state를 구조화하는 데 가장 중요한 원칙은 중복배제원칙(Don’t Repeat Yourself) ⇒ DB 의 정규화와 유사
- 애플리케이션이 필요로 하는 가장 최소한의 state를 파악하고 나머지 모든 것들은 필요에 따라 실시간으로 계산
state 가 아닌 것
- 시간이 지나도 변하지 않는 것: 상수
- 부모로부터 props를 통해 전달되는 것: 외부에 종속된 데이터로, 내부의 상태가 아님
- 컴포넌트 안의 다른 state나 props를 가지고 계산 가능한 것: 최소한의 state 가 아님
state 의 위치
- 해당 state를 기반으로 렌더링하는 모든 컴포넌트를 찾기
- 그들의 가장 가까운 공통되는 부모 컴포넌트를 찾기 - 계층에서 모두를 포괄하는 상위 컴포넌트
- state가 어디에 위치 돼야 하는지 결정
- 대개, 공통 부모에 state를 그냥 두기
- 혹은, 공통 부모 상위의 컴포넌트에 두기
- state를 소유할 적절한 컴포넌트를 찾지 못하였다면, state를 소유하는 컴포넌트를 하나 만들어서 상위 계층에 추가하기
⇒ state 의 위치를 파악할 때 위의 조건을 상기할 것!
UI 표현하기
컴포넌트 import 및 export 하기
- React에서는
'./Gallery.js'
또는 './Gallery'
둘 다 사용할 수 있지만 전자의 경우가 native ES Modules 사용 방법에 더 가깝다.
컴포넌트에 props 전달하기
JSX spread 문법으로 props 전달하기
- props를 직접 사용하지 않기 때문에 보다 간결한 “spread” 문법을 사용하는 것이 합리적일 수 있다.
- spread 문법은 제한적으로 사용하세요. 다른 모든 컴포넌트에 이 구문을 사용한다면 문제가 있는 것이다.
- 자식을 JSX로 전달해야 해서 spread 를 여러 번 사용하지 않게 방지할 수 있음
시간에 따라 props가 변하는 방식
- props는 컴퓨터 과학에서 “변경할 수 없다”라는 의미의 불변성을 가지고 있다.
- 컴포넌트가 props를 변경해야 하는 경우(예: 사용자의 상호작용이나 새로운 데이터에 대한 응답): 부모 컴포넌트에 다른 props, 즉 새로운 객체를 전달하도록 “요청”해야 한다
- 이전의 props는 버려지고, 기존 props가 차지했던 메모리가 회수된다.
- Props는 변경할 수 없다. 상호작용이 필요한 경우 state를 설정해야 한다.
⇒ props 는 렌더링 시마다 불변의 값을 가진다. 렌더링 시에 props 를 변경하는 행위를 해서는 안 된다. ex) props.value = props.value + 1
조건부 렌더링
조건부로 null
을 사용하여 아무것도 반환하지 않기
if (isPacked) {
return null;
}
return <li className="item">{name}</li>;
- 실제로 컴포넌트에서
null
을 반환하는 것은 개발자가 렌더링하려고 할 때 놀랄 수 있기 때문에 흔한 경우는 아니다.
⇒ null 을 반환하는 대신 상위에서 조건절을 통해서 컴포넌트 렌더링을 막는 방식을 사용하자.
if (isPacked) {
return <li className="item">{name} ✅</li>;
}
return <li className="item">{name}</li>;
상호작용성 더하기
State: 컴포넌트의 기억 저장소
hook 규칙
- 훅(
use
로 시작하는 함수들)은 컴포넌트의 최상위 수준 또는 커스텀 훅에서만 호출할 수 있다.
- 조건문, 반복문 또는 기타 중첩 함수 내부에서는 훅을 호출할 수 없습니다.
연관된 state 하나로 합치기
- 서로 연관이 없는 경우 여러 개의 state 변수를 가지는 것이 좋다.
- 하지만 두 state 변수를 자주 함께 변경하는 경우에는 두 변수를 하나로 합치는 것이 더 좋을 수 있다.
State 업데이트 큐
batching
- React는 state 업데이트를 하기 전에 이벤트 핸들러의 모든 코드가 실행될 때까지 기다린다.
- React 앱을 훨씬 빠르게 실행할 수 있게 해준다.
- 일부 변수만 업데이트된 “반쯤 완성된” 혼란스러운 렌더링을 처리하지 않아도 된다.
- React는 클릭과 같은 여러 의도적인 이벤트에 대해 batch를 수행하지 않으며, 각 클릭은 개별적으로 처리된다.
- React는 안전한 경우에만 batch를 수행한다.
⇒ 안전한 경우 라는 것이 무엇인가..
객체 state 업데이트하기
state 값은 읽기 전용처럼 다루어야 한다.
여러 필드에 단일 이벤트 핸들러 사용하기
function handleChange(e) {
setPerson({
...person,
[e.target.name]: e.target.value
});
}
immer
- Immer가 제공하는
draft
: Proxy
- 내부적으로
draft
의 어느 부분이 변경되었는지 알아내어, 변경사항을 포함한 완전히 새로운 객체를 생성
배열 State 업데이트하기
배열 내부의 객체 업데이트하기
- 중첩된 state를 업데이트할 때, 업데이트하려는 지점부터 최상위 레벨까지의 복사본을 만들어야 한다.
- 일반적으로 깊은 레벨까지의 state를 업데이트할 필요는 없다. state 객체가 매우 깊다면 평탄하게 만드는 것을 고려해야 한다.
- state 구조를 변경하고 싶지 않다면, Immer 사용할 수 있다.
스터디 1차 후기
느낀 점
문서에 써있음에도 읽어보지 않아 몰랐던 내용이 많았습니다. 기본적인 컨벤션부터 내부 동작원리까지 문서에 적혀있는 부분이 많아 신기했습니다. 공식 문서에서 immer 를 적극(?) 활용하라고 권유하는 부분이나, useEffect 를 사용하지 않아도 되는 여러 사례들이 제일 인상적이었습니다.
궁금한 점
문서를 읽으면서 조금 더 깊게 고민해보고자 하는 내용들입니다. 다음 포스팅에서 다루도록 하겠습니다.
-
파일 확장자를 쓰는 게 왜 esm 문법에 더 맞는 것인가?
-
export default / named export 의 장단점
-
hook 앞에 use 라는 prefix 를 제한해둘 수 있는 동작의 근거가 무엇인가? (내부 코드 파악하기)
-
내부적으로 fragment 를 만나면 createElement 가 어떻게 동작하는가?
-
렌더 트리와 가상돔의 관계
https://velog.io/@minbr0ther/React.js-Virtual-DOM-가상-돔#2️⃣-virtual-dom의-등장
-
state update 시, batching 이 되는 시점과 조건
-
context api / vue의 provide-inject, 전역 상태 관리 라이브러리와의 장단점
-
제어 컴포넌트 / 비제어 컴포넌트의 차이
https://velog.io/@yukyung/React-제어-컴포넌트와-비제어-컴포넌트의-차이점-톺아보기
-
flushSync 를 언제 사용하는지
https://ko.react.dev/reference/react-dom/flushSync