# 2024. 09.
# 09. 01.
# React에서 key는 내부적으로 어떻게 처리될까?
React는 내부적으로 key를 통해 컴포넌트 인스턴스를 해시맵 형태로 저장한다. 이 후 리렌더링 과정에서 React는 이전 렌더링의 key-인스턴스 맵을 참조하고 동일한 key를 가진 새 엘리먼트가 발견되면, React는 해당 인스턴스를 재사용한다.
react/react-reconciler/ReactChildFiber.js - updateSlot (opens new window)
해당 코드에서 이전 key가 존재하면 (opens new window) updateElement를 호출하여 재사용해주고, 존재하지 않으면 (opens new window) null을 반환해서 Fiber를 새로 생성하는 과정을 거친다.
# 09. 02.
# 컴포넌트 다시 생각하기
# 09. 04.
# React Lane은 내부적으로 어떻게 동작할까?
Lane은 React에서 관리하는 비트 단위의 우선순위로 32개(0~31)로 이루어져있다.
// Lane values below should be kept in sync with getLabelForLane(), used by react-devtools-timeline.
// If those values are changed that package should be rebuilt and redeployed.
export const TotalLanes = 31;
export const NoLanes: Lanes = /* */ 0b0000000000000000000000000000000;
export const NoLane: Lane = /* */ 0b0000000000000000000000000000000;
export const SyncLane: Lane = /* */ 0b0000000000000000000000000000001;
export const InputContinuousHydrationLane: Lane = /* */ 0b0000000000000000000000000000010;
export const InputContinuousLane: Lanes = /* */ 0b0000000000000000000000000000100;
export const DefaultHydrationLane: Lane = /* */ 0b0000000000000000000000000001000;
export const DefaultLane: Lanes = /* */ 0b0000000000000000000000000010000;
const TransitionHydrationLane: Lane = /* */ 0b0000000000000000000000000100000;
const TransitionLanes: Lanes = /* */ 0b0000000001111111111111111000000;
const TransitionLane1: Lane = /* */ 0b0000000000000000000000001000000;
const TransitionLane2: Lane = /* */ 0b0000000000000000000000010000000;
const TransitionLane3: Lane = /* */ 0b0000000000000000000000100000000;
const TransitionLane4: Lane = /* */ 0b0000000000000000000001000000000;
const TransitionLane5: Lane = /* */ 0b0000000000000000000010000000000;
const TransitionLane6: Lane = /* */ 0b0000000000000000000100000000000;
const TransitionLane7: Lane = /* */ 0b0000000000000000001000000000000;
const TransitionLane8: Lane = /* */ 0b0000000000000000010000000000000;
const TransitionLane9: Lane = /* */ 0b0000000000000000100000000000000;
const TransitionLane10: Lane = /* */ 0b0000000000000001000000000000000;
const TransitionLane11: Lane = /* */ 0b0000000000000010000000000000000;
const TransitionLane12: Lane = /* */ 0b0000000000000100000000000000000;
const TransitionLane13: Lane = /* */ 0b0000000000001000000000000000000;
const TransitionLane14: Lane = /* */ 0b0000000000010000000000000000000;
const TransitionLane15: Lane = /* */ 0b0000000000100000000000000000000;
const TransitionLane16: Lane = /* */ 0b0000000001000000000000000000000;
const RetryLanes: Lanes = /* */ 0b0000111110000000000000000000000;
const RetryLane1: Lane = /* */ 0b0000000010000000000000000000000;
const RetryLane2: Lane = /* */ 0b0000000100000000000000000000000;
const RetryLane3: Lane = /* */ 0b0000001000000000000000000000000;
const RetryLane4: Lane = /* */ 0b0000010000000000000000000000000;
const RetryLane5: Lane = /* */ 0b0000100000000000000000000000000;
export const SomeRetryLane: Lane = RetryLane1;
export const SelectiveHydrationLane: Lane = /* */ 0b0001000000000000000000000000000;
const NonIdleLanes = /* */ 0b0001111111111111111111111111111;
export const IdleHydrationLane: Lane = /* */ 0b0010000000000000000000000000000;
export const IdleLane: Lanes = /* */ 0b0100000000000000000000000000000;
export const OffscreenLane: Lane = /* */ 0b1000000000000000000000000000000;
Lane은 Fiber의 우선순위를 가르키고 있으며 Fiber에서 관리한다. Fiber는 본인의 Lane과 자식들의 Lane(ChildLane)정보를 가지고 있다. React는 렌더링 재조정 과정에서 우선순위가 높은 Fiber를 우선적으로 렌더링한다. 대부분 업데이트는 1번 우선순위인 Sync Lane이고 개발자가 useTransition이나 useDeferredValue 등을 이용해서 우선순위를 설정할 수 있다. Fiber가 상태 변화로 Lane이 설정될 때, 해당 Lane은 부모 Fiber의 ChildLane에 비트 | 연산으로 합쳐진다. 리렌더링 과정에서 React는 Root의 childLane을 확인하고 우선순위가 가장 높은 lane부터 처리한다. lane을 통해 어느 자식을 리렌더링 해야될지 알게되는데 Root부터 childLane을 검사해 자식 Fiber의 childLane을 각각 확인하여 렌더링해야되는 Fiber인지 알게된다. React는 한번의 렌더링 사이클 (render phase + commit phase)당 하나의 Lane을 처리할 수 있고 이런식으로 우선순위가 높은 Lane부터 하나씩 처리하게 된다.
# 09. 05.
# SSL 동작 과정
비대칭키는 두가지 역할을 할 수 있다. 암호화
, 서명
암호화
- 암호화, 복호화로 구성
- 원문값을 볼 수 없음
서명
- 서명, 검증으로 구성
- 해당 원문에 서명을 검증하는 것을 목표
- 원문값을 볼 수 있음
- CA에서 서버의 공개키를 CA의 비밀키로
서명
(인증서) → CA의 비밀키로만 검증 가능 - 브라우저가 서버에 접속하면 서버에서 인증서 제공.
- 브라우저는 전달받은 인증서를 CA의 공개키로 검증.
- 이 때 대부분의 CA 공개키는 브라우저에 내장되어있음. 없는 경우 네트워크를 통해 공개키 요청
- 브라우저에서 서버와 통신하기 위한 대칭키 생성하여 인증서 내의 서버의 공개키로
암호화
하여 서버에 전달 → 서버의 비밀키로만 복호화 가능 - 서로 공유된 대칭키로
암호화
하여 통신
# 09. 06.
# React ErrorBoundary에서 fetch 에러를 catch 하지 못하는 이유
React에서는 class component의 getDerivedStateFromError
메소드로 컴포넌트에서 throw하는 에러를 catch할 수 있다.
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
// 다음 렌더링에서 폴백 UI가 보이도록 상태를 업데이트 합니다.
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
// 에러 리포팅 서비스에 에러를 기록할 수도 있습니다.
logErrorToMyService(error, errorInfo);
}
render() {
if (this.state.hasError) {
// 폴백 UI를 커스텀하여 렌더링할 수 있습니다.
return <h1>Something went wrong.</h1>;
}
return this.props.children;
}
}
하지만 fetch에서 throw 하는 에러는 catch하지 못하는데 그 이유는 바로 실행 컨텍스트가 다르기 때문이다. React는 동일한 실행컨텍스트 내에서 발생하는 에러만 핸들링 할 수 있다. fetch가 실행되는 시점은 V8 엔진의 콜스택이지만, 비동기적으로 Web API에서 별도의 실행 컨텍스트에서 실행되고, 이 Web API는 C++ 등의 네이티브 언어로 개발 되었기에 여기서 말하는 실행 컨텍스트는 C++의 실행컨텍스트이다. 즉, 브라우저에 console에 출력되는 fetch 에러 메세지도 C++에서 출력된 것 이므로 V8 엔진 실행컨텍스트에서 C++ 실행컨텍스트에서 발생한 에러를 catch 할 방법은 없기에 ErrorBoundary가 catch 할 수 없다.
이를 해결하기 위해선 비동기 작업이 끝난 이후 응답에 따라 Javascript 실행 컨텍스트 내에서 throw 해주면 ErrorBoundary가 catch 할 수 있다.