-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
505 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
.DS_Store | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
# 01장 리액트 개발을 위해 꼭 알아야할 자바스크립트 | ||
|
||
## JS 타입과 동등 비교 | ||
|
||
> 리엑트의 상태들은 동등비교, 얕은 비교를 기반으로 이루어짐 | ||
**JS의 데이터 타입** | ||
|
||
원시타입 | ||
|
||
- boolean, number, null, undefiend, string, symbol, bigint | ||
|
||
객체 타입 | ||
|
||
- object | ||
|
||
**Falsy** | ||
|
||
false, 0, NaN, ‘’, null, undefiend… -0? | ||
|
||
**Object.is** | ||
|
||
Object.is는 강제 형변환을 하지않고 타입 비교를하며, 두 개의 인수가 동일한지 구분할 수 있다. | ||
|
||
BUT 객체에대해서는 못한다. (기존 === 보다 개선된정도인듯) | ||
|
||
```jsx | ||
Number.NaN === NaN; // false | ||
Object.is(Number.NaN, NaN); // true | ||
Object.is({}, {}); // false | ||
``` | ||
|
||
React에서는 ES6부터 제공되는 Object.is를 통해서 동등비교를 한다. | ||
|
||
추가적으로 React에서는 `shallowEqual`를 만들어 1Depth까지는 비교가 가능할 수 있도록했다. | ||
|
||
왜냐하면 JSX Props는 객체이고 이를 비교만하면 된다고 설계했기때문?! | ||
|
||
```jsx | ||
function Foo() { | ||
return <Bar hi="hi!"> | ||
} | ||
|
||
funtion Bar(props) { | ||
return <p>{props.hello}<p> | ||
} | ||
``` | ||
|
||
## 함수 | ||
|
||
함수 선언 방식 | ||
|
||
- 함수 선언문 `function foo() {}` | ||
- 함수 표현식 `const foo = function () {}` | ||
|
||
이두가지는 호이스팅의 차이가 있겠다. | ||
|
||
- new Function `const bar = new Function('a','b','return a + b')` | ||
- Arrow Function `const bar = (a,b) => a + b` | ||
- constructor, argument가 없으며, 선언 당시의 상위 this를 참조한다. | ||
|
||
**함수 주의사항** | ||
|
||
1. **함수의 side effect를 최대한 억제하라.** | ||
1. side-effect를 처리하는 useEffect는 사용은 최소화해야된다. | ||
2. 함수의 역할을 좁히고, 컴포넌트의 안정성을 올릴 수 있음 | ||
2. 가능한 함수를 작게 만들어라. | ||
1. 함수의 원래의 목적인 재사용성에 좋도록 가볍게 만들려고해라. | ||
3. 누구나이해할 수 있는 이름으로 만들어라. | ||
```jsx | ||
useEffect(function apiRequest() {}, []); // 처럼 명확하게 붙혀보는것도 좋을 것 같다. 나름 꿀팁 | ||
``` | ||
|
||
## 클래스 | ||
|
||
constructor, property, getter, setter, instance method ,static method | ||
|
||
## 클로저 | ||
|
||
함수형 리액트 컴포넌트의 훅, 의존성 배열, 구조등 주요 기술이 모두 클로저에 의존한다. | ||
|
||
쉽게 코드가 선언된 순간에 정적으로 결정된 환경의 조합 | ||
|
||
```jsx | ||
function foo() { | ||
var x = 1; | ||
function bar() { | ||
console.log(x); // 선언될 당시 랙시컬(어휘전) 환경에 x가 존재함 해서 출력가능 | ||
} | ||
|
||
return bar; | ||
} | ||
foo()(); // 1 | ||
``` | ||
|
||
**스코프 (유효범위)** | ||
|
||
- 전역 스코프: global, window | ||
- 함수 스코프 | ||
- 블록 스코프 | ||
|
||
**`setState((prev) => prev + 1)`** | ||
|
||
react에서는 useState를 보면 클로저를 활용해서 set, get를 반환해서 보호하고, 지속해서 해당 state가 사용될 수 있도록 환경을 유지해줌. | ||
|
||
## 이벤트 루프 | ||
|
||
보통 JS는 싱글스레드 동기방식으로 작동한다. | ||
|
||
이벤트 루프는 이런 JS에서 비동기적인 방식을 처리할 수 있게함. | ||
|
||
어떻게 호출 스택이 비었으면 테스크큐의 실행작업들을 호출스택으로 넣음 | ||
|
||
- 호출 스택 | ||
- 태스크 큐 : setTimeout, interval, immediate | ||
- 마이크로 태스크 큐: process.nextTick, promise, mutationObserver | ||
|
||
> \*requestAnimationFrame: 리패인트 전 호출된다. | ||
> 랜더링은 마이크로 태스크 큐가 끝날때마다 기회를 얻는다. | ||
## 타입스크립트 | ||
|
||
**any → unknown 사용** | ||
|
||
- 이후 type guard, narrowing등 타입에 맞게 사용할 수 있도록해야됨 | ||
- instanceof, typeof, in 을 활용해보쟈 | ||
|
||
**제네릭** | ||
|
||
다양한 타입에 대응하게 만들 수 있도록도와줌 `useState<string>('')` | ||
|
||
**덕타이핑** | ||
|
||
구조적으로 동일하면 동일한 타입 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
# 리액트 핵심 요소 깊게 살펴보기 | ||
|
||
리액트에서 자주 언급되는 핵심 개념을 깊게 알아본다! | ||
|
||
## JSX | ||
|
||
JSX는 리액트가 등장하면서 페이스북에서 소개 된 구문 이지만, 리액트에 종속되지 않은 독자적인 문법이다. 자바스크립트 내부에서 표현하기 까다로웠던 XML 스타일 트리 구문을 작성하는데 많은 도움을 주는 문법이다. | ||
|
||
- `JSXElement` `JSXAttribute` `JSXChildren` `JSXString` 4가지 컴포넌트를 기반으로 구성되어 있다. | ||
|
||
## 가상 DOM과 리액트 파이버 | ||
|
||
가상DOM은 웹페이지에 대한 인터페이스로 브라우저가 웹페이지의 콘텐츠와 구조를 어떻게 보여줄지에 대한 정보를 담고있다. 가상 DOM은 DOM을 관리하는 브라우저 보다 무조건 빠른것이 아닌, 대부분의 상황에서 빠르다는 것 이다. | ||
|
||
리액트 파이버는 브라우저가 아닌 환경에서도 적용 될 수 있기 때문에 가상 DOM과 동일한 개념은 아니다. | ||
|
||
``` | ||
최근에 million(https://million.dev/) 이라는 라이브러리를 보았는데, 이건 이런 최적화 성능을 70퍼센트 끌어올렸다고 자랑하더라고요! | ||
``` | ||
|
||
#### 리액트 파이버란 | ||
|
||
리액트에서 관리하는 평범한 자바스크립트 객체이고, 애니메이션 레이아웃 등 사용자 인터렉션에 반응성 문제를 해결한다. 파이버의 모든 과정은 비동기로 일어난다. | ||
|
||
- 파이버 재조정자(fiber reconciler)는 가상 DOM과 실제 DOM을 비교해 변경 사항이 있으면 렌더링을 요청하는 역할을 한다. | ||
- 재조정(reconciliation)은 가상DOM 실제DOM을 비교하는 작업(알고리즘) 이다. | ||
|
||
#### 스택 알고리즘 | ||
|
||
원래 스택에 렌더링에 필요한 작업을 쌓으며 동기적으로 진행되고, 자바스크립트의 싱글스레드 특성 상 동기작업은 중단 되지 못해 이 방식은 비효율적이 되어 버렸다. 이 문제를 해결하기 위해 파이버라는 개념을 도입했다. | ||
|
||
#### 리액트 파이버 구현 | ||
|
||
리액트 파이버는 하나의 작업단위로 구성되어 있으며, `finishedWork()` 함수로 작업을 마무리한다. **렌더 단계**와 **커밋 단계** 2가지로 나뉘어 브라우저 DOM에 가시적인 변경사항을 만들어낸다. | ||
|
||
- 렌더단계, 사용자에게 노출되지 않는 비동기작업들을 수행한다. | ||
- 커밋단계, DOM에 실제 변경사항을 반영하기 위한 작업을 동기적으로 수행한다. | ||
|
||
#### 리액트 파이버 트리 | ||
|
||
리액트 파이버 트리에서는 현재의 모습을 담은 트리와 작업 상황을 담은 workInProgress 트리가 있다. 리액트 파이버의 작업이 끝나면 포인터만 변경하여 workInProgress 트리를 현재 트리로 바꿔버린다. 이 과정을 더블버퍼링 과정이라고 하며, 커밋 단계에서 수행된다. | ||
|
||
## 클래스형과 함수형 컴포넌트 | ||
|
||
초기 함수형 컴포넌트는 단순히 요소를 정적으로 렌더링 하는 것이 목표였지만, 16.8 업데이트 이후 달라졌다. | ||
|
||
#### 클래스형 컴포넌트 | ||
|
||
클래스형 컴포넌트를 사용하며 가장 많이 언급되는 것은 생명주기 이다. | ||
|
||
- Mount, 컴포넌트가 생성 되는 시점 | ||
- Update, 이미 생성된 컴포넌트가 업데이트 되는 시점 | ||
- Unmount, 컴포넌트가 더 이상 존재하지 않는 시점 | ||
|
||
#### 클래스형 컴포넌트의 Render() | ||
|
||
항상 순수해야하며 Side Effect가 없어야한다. render 함수 내부에서 setState를 호출해서는 안된다. | ||
|
||
#### Pure Component와 일반 Component | ||
|
||
shouldComponentUpdate 생명주기를 다룸에 있어서 차이가 있다. Pure Component는 얕은 비교만 진행하여 변경사항이 있을 경우 재 렌더링 시킨다. | ||
|
||
#### ErrorBoundary | ||
|
||
componentDidCatch는 개발모드와 프로덕션모드에서 다르게 동작한다. 개발모드에서는 에러가 발생하면 window까지 전파되고, 프로덕션모드에서는 잡히지 않는 에러만 전파된다. | ||
|
||
#### 클래스형 컴포넌트의 한계 | ||
|
||
- 데이터 흐름을 추적하기 어렵다 | ||
- 애플리케이션 내부 로직의 재사용이 어렵다. | ||
- 기능이 많아질수록 컴포넌트 크기가 커진다. | ||
- 클래스는 함수에 비해 상대적으로 어렵다. | ||
|
||
#### 클래스형 VS 함수형 | ||
|
||
클래스형은 항상 this를 참조하기에 중간에 값이 변경되는 경우 변경 된 값이 렌더링되고, 함수형은 렌더링이 일어난 순간의 값을 가지고 사용한다. | ||
|
||
## 렌더링은 어떻게 일어나는가? | ||
|
||
리액트에도 렌더링이라는 과정이 있으며, 비용이 소모되기 때문에 렌더링 과정을 최소한으로 줄여야한다. | ||
|
||
### 리액트에 렌더링이 일어나는 이유 | ||
|
||
리액트에서 렌더링이 일어나는 타이밍은 아래와 같다. | ||
|
||
- 최초 렌더링 | ||
- 클래스형 컴포넌트의 setState | ||
- 클래스형 컴포넌트의 foreceUpdate | ||
- 함수형 컴포넌트의 useState의 setter가 실행되는 경우 | ||
- 함수형 컴포넌트의 useReducer의 두 번째 요소인 dispatch가 실행되는 경우 | ||
- 컴포넌트의 key props가 변경 되는 경우 | ||
- props가 변경되는 경우 | ||
- 부모 컴포넌트가 리렌더링 되는 경우 | ||
|
||
### Key Props가 필요한 이유 | ||
|
||
리렌더링이 발생하는 동안 동일한 요소를 식별하는 식별값이고, 리액트 파이버의 현재와 workInProgress를 구분하는 값이다. 만약 키가 없다면, 단순한 파이버 내부의 index로만 비교하게 된다. | ||
|
||
### 상태관리 라이브러리 | ||
|
||
mobx나 redux 같은 라이브러리들은 각자의 방법으로 상태관리를 해주다가 위의 리렌더링 트리거를 통해 리렌더링을 발생 시킨다. | ||
|
||
### 렌더와 커밋 | ||
|
||
렌더 단계는 type,props,key 크게 3가지를 비교하여 변경이 필요한 컴포넌트인지 체크한다. 다음인 커밋단계에서 변경 사항을 실제 DOM에 적용한다. 하지만 이와같은 리액트 렌더링과정이 일어났다고 하여 무조건 DOM 업데이트가 일어나는 것은 아니다. | ||
|
||
React 18에서 비동기 렌더링을 통해 먼저 보여줄 수 있는 화면을 먼저 보여주는 동시성 렌더링이 업데이트 되었다. | ||
|
||
## 컴포넌트와 함수의 무거운 연산을 기억해 두는 메모이제이션 | ||
|
||
무조건 메모이제이션이 필요하다 라는 입장과 섣불리 해서는 안된다라는 2가지 입장이 있다. | ||
|
||
### 꼭 필요한 곳에만 메모이제이션을 추가 해야 한다. | ||
|
||
- 메모이제이션에도 비용이 들어간다. | ||
- 간단한 작업의 경우 비용이 더 들어갈 수 있다. | ||
- 리액트 공식문서에서는 useMemo를 사용하지 않고도 작동할 수 있는 코드를 작성하는것을 권하고 있다. | ||
|
||
### 렌더링 과정의 비용은 비싸다! 모두 메모이제이션 해버리자 | ||
|
||
- 자식컴포넌트가 많은 경우, memo를 때려버리는것이 이득이다 | ||
- 프로젝트 규모가 커지는 경우 메모이제이션이 필요한 컴포넌트만 세심하게 볼 수 없다. | ||
- 메모이제이션 되지 않았을 경우 발생하는 리렌더링(객체 재생성)의 비용이 더 크다. | ||
- 사람의 실수로 인한 비용 문제도 있다. | ||
|
||
``` | ||
글쓴이도 후자에 좀 더 이점이 크다고 말했는데 저도 비슷하게 생각합니다. | ||
작업자가 작업을 하면서 생각을 덜 하게 해주는 부분도 꽤 크다고 생각합니다. 다들 이 부분에 대해서 어떻게 생각하시나요? | ||
``` |
Oops, something went wrong.