3. Capture phase events (e.g.onClickCapture) 가 이제 진짜 캡처 페이즈 리스너 사용 (이전엔 어케했누?)
이벤트 풀링 최적화 제거 (No Event Pooling)
“event pooling” optimization이 별 의미없어서 삭제
비동기적으로 이벤트 객체에 접근 불가능했던게 삭제됨
function handleChange(e) {
setData(data => ({
...data,
// This crashes in React 16 and earlier:
text: e.target.value <- before v17 : null
}));
}
난 2021 입문자라(react 17 이후 사용) event pooling이 무슨 역할이었는지 정확히는 모르겠다
SyntheticEvent 객체는 이벤트 핸들러가 호출된 후 초기화되기에, 비동기적으로 이벤트 객체에 접근할 수 없었던 것이 수정되었다고 한다.
아마 setData 실행시기와 e의 생명주기가 일치하지 않았던것(초기화되버려서)으로 추론된다.
Effect Cleanup Timing
useEffect(() => {
// This is the effect itself.
return () => { // This is its cleanup. };});
useEffect가 보다 효율적으로 변경
기본 컨셉 :
Most effects don’t need to delay screen updates, so React runs them asynchronously soon after the update has been reflected on the screen.
(For the rare cases where you need an effect to block paint, e.g. to measure and position a tooltip, preferuseLayoutEffect.)
그러나 보통은 unmounting 될때 cleanup function은 보통 동기적으로 실행되게 사용되어 왔다.
(similar tocomponentWillUnmountbeing synchronous in classes)
이것은 탭 변경과 같은 큰 페이지 변경시 속도 저하를 초래했다.
그래서 React 17에서는 항상 cleanup function은 비동기적으로 실행되게 변경되었다.
(In React 17, the effect cleanup function always runs asynchronously — for example, if the component is unmounting, the cleanup runsafterthe screen has been updated.)
동기적 상황을 원하면 useLayoutEffect를 쓰시라
(you might want to rely on the synchronous execution, you can switch touseLayoutEffectinstead)
추가적으로 cleanup function은 언제나 new Effect가 실행하기 전에 실행된다.
let Button = forwardRef(() => {
// We forgot to write return, so this component returns undefined.
// React 17 surfaces this as an error instead of ignoring it.
<button />;
});
let Button = memo(() => {
// We forgot to write return, so this component returns undefined.
// React 17 surfaces this as an error instead of ignoring it.
<button />;
});
return undefined하면 에러
(제대로 return 안하면 에러)
만약 아무것도 return 하지 않는 것을 명시적으로 나타내고 싶다면 return null 사용
배치 : React가 더 나은 성능을 위해 여러 개의 state 업데이트를 하나의 리렌더링 (re-render)로 묶는 것을 의미)
React 18의 createRoot를 통해, 모든 업데이트들은 어디서 왔는가와 무관하게 자동으로 배칭되게 된다.
이 뜻은, 추가적으로 timeout, promise, native 이벤트 핸들러와 모든 여타 이벤트는 React에서 제공하는 이벤트와 동일하게 state 업데이트를 배칭할 수 있다. 이를 통해 우리는 렌더링을 최소화하고, 나아가 애플리케이션에서 더 나은 성능을 기대한다.
상태 업데이트에 배치가 적용되지 않았으면 하는 경우엔 새롭게 추가된ReactDOM.flushSync함수를 사용
useTransition
React 17 까지는 상태 업데이트를 긴급 혹은 전환으로 명시하는 방법 X
모든 상태 업데이트는 긴급 업데이트 → setTimeout이나 throttle, debounce 등의 테크닉을 써서 긴급 업데이트 방해를 우회하는 것이 최선이였다
useTransition을 쓰면
일부 상태 업데이트를 긴급하지 않은 것 (not urgent)로 표시
이것으로 표시되지 않은 상태 업데이트는 긴급한 것으로 간주
긴급한 상태 업데이트 (input text 등)가 긴급하지 않은 상태 업데이트 (검색 결과 목록 렌더링)을 중단할 수 있다.
쓰는 이유 : 느린 렌더링 & 느린 네트워크
업데이트를 긴급한 것과 긴급하지 않은 것으로 나누어 개발자에게 렌더링 성능을 튜닝하는데 많은 자유를 주었다고 볼 수 있다.
useId
useId는 클라이언트와 서버간의 hydration의 mismatch를 피하면서 유니크 아이디를 생성할 수 있는 새로운 훅이다. 이는 주로 고유한 id가 필요한 접근성 API와 사용되는 컴포넌트에 유용할 것으로 기대
useDeferredValue
useDeferredValue를 사용하면, 트리에서 급하지 않은 부분의 재렌더링을 지연
지연된 렌더링을 인터럽트하고 사용자 입력을 차단할때 사용
이는 debounce와 비슷하지만, 몇가지 더 장점이 있다.
지연된 렌더링은 인터럽트가 가능하며, 사용자 입력을 차단하지 않는다.
***** 아래는 Library author들에게 권장하는 hook들*****
(아직 어디에 쓰는진 잘..? library 제작자한테 추천한다고 한다 특히 useSyncExternalStore)
useSyncExternalStore
스토어에 대한 업데이트를 강제로 동기화 하여 외부 스토어가 concurrent read를 지원할 수 있도록 하는 새로운 훅
**useEffect**가 필요하지 않고, 이는 리액트 외부 상태와 통합되는 모든 라이브러리에 권장된다.
용어 설명 :
External Store: 외부 스토어라는 것은 우리가 subscribe하는 무언가를 의미한다. 예를 들어 리덕스 스토어, 글로벌 변수, dom 상태 등이 될 수 있다.
Internal Store: propscontextuseStateuseReducer 등 리액트가 관리하는 상태를 의미한다.
Tearing: 시각적인 비일치를 의미한다. 예를 들어, 하나의 상태에 대해 UI가 여러 상태로 보여지고 있는, (= 각 컴포넌트 별로 업데이트 속도가 달라서 발생하는) UI가 찢어진 상태를 의미한다.
css-in-js 라이브러리가 렌더링 도중에 스타일을 삽입할 때 성능 문제를 해결할 수 있는 새로운 훅
The signature is identical to useEffect, but it fires synchronously before all DOM mutations.
리액트가 DOM을 변환한경우, 레이아웃에서 무언가를 읽기전 (**clientWidth**와 같이) 또는 페인트를 위해 브라우저에 값을 전달하기 전에 DOM에 대한 다른 변경과 동일한 타이밍에 작업을 하면 된다.
→ We must ensure to manipulate the CSS rules at the same time as other changes to the DOM. It can be when React mutates the DOM, before anything is read from the layout and before the content is visible in the browser.
useLayoutEffect 과 비슷,
hook is used to read the layout from the DOM and synchronously re-render.
위와 같은 코드를 실행하면 상태 변경 merge됨 (The merging is shallow, sothis.setState({comments})leavesthis.state.postsintact, but completely replacesthis.state.comments.)
- 데이터는 단방향(아래로 흐른다)
Event
- 이벤트는 합성 이벤트
function Form() {
function handleSubmit(e) {
e.preventDefault(); console.log('You clicked submit.');
}
return (
<form onSubmit={handleSubmit}>
<button type="submit">Submit</button>
</form>
);
}
여기서 e는 리엑트 고유의 합성 이벤트(synthetic event)라 cross-browser 호환성을 걱정하지 않아도 된다
제어 컴포넌트 (Controlled Component)
<input>, <select> 등이 있을때 컴포넌트의 상태, props로 주어진 값을 활용하는 컴포넌트
ex) input 태그의 value 값을 useState로 제어)
비제어 컴포넌트
<input> 등이 자체적으로 상태를 갖는 경우 - (useRef등으로 관리)
해당 데이터와 UI의 동기가 이뤄지진 않으니 주의 (해당 상태가 변해도 컴포넌트의 상태가 변한게 아니므로 리렌더링이 일어나지 않는다)
ex) <input type="file"/> 의 경우 File API를 통해 js로 조작 가능한데 값이 읽기 전용이고 사용자만이 값 설정이 가능해서 비제어 컴포넌트
Key
가상돔 갱신할때 휴리스틱한 알고리즘으로 연산 속도를 돕는다
가정 :
서로 다른 타입의 두 엘리먼트는 서로 다른 트리를 만들어낸다.
개발자가keyprop을 통해, 여러 렌더링 사이에서 어떤 자식 엘리먼트가 변경되지 않아야 할지 표시해 줄 수 있다.
비교대상 - sibling
배열의 index를 key로 사용시 뒤죽박죽 되므로 변하지 않고 예상 가능한 '유일값' 사용
Anycast는 각각 동일한 IP 주소가 할당된 엔드포인트 그룹에 여러 라우팅 경로를 제공하는 기술 - microsoft
??? 이렇게 말하면 무슨 말인지 감이 잡히지 않는다.
보통 우리가 알고 있는 IP는 '고유한' 주소이고, Unicast IP이다.
우선 unicast가 뭔지 알고 넘어가야 될꺼 같다.
참고)
그림 출처 : https://microchipdeveloper.com/tcpip:tcp-vs-udp
유니캐스트 (Unicast) - 1 : 1
유니캐스트는 정보를 전송하기 위한 프레임에 자신의 MAC 주소와 목적지의 MAC 주소를 첨부하여 전송
브로드캐스트 (Broadcast) 1 : N
브로드캐스트 방식은 로컬 네트워크에 연결되어 있는 모든 시스템에게 프레임을 보내는 방식
멀티캐스트(Multicast) 1: N (특정 그룹)
멀티캐스트는 네트워크에 연결되어 있는 시스템 중 일부에게만 정보를 전송하는 것으로 특정 그룹에 속해 있는 시스템에게만 한 번에 정보를 전송할 수 있는 방법
라우터가 멀티캐스트를 지원해야만 사용 가능하다는 단점
멀티캐스트 전송이 지원되면 송신자는 여러 수신자에게 한 번에 메시지가 전송되도록 하여
데이터의 중복 전송으로 인한 네트워크 자원 낭비를 최소화할 수 있게 된다.
멀티캐스트 전송을 위해서는 헤더에 수신자의 주소 대신 수신자들이 참여하고 있는 그룹 주소를 표시하여 패킷을 전송한다.
Anycast란?
Anycast IP는 서로 다른 호스트끼리 동일한 IP 주소를 가질 수 있는 개념이다.
링크 계층(L2)에서 맥 주소를 보고 데이터를 전달할때는 충돌이 일어나면 사용이 불가능하지만
라우터(L3)에서는 네트워크 라우팅 알고리즘(BGP)을 통해 가장 가까운곳으로 판단되는 쪽으로 사용 가능한 식으로 구현되어 있다.
anycast는 주로 DNS 서비스에 많이 활용되고 있다는데 지역별로 DNS 서버를 분산하고, 항상 네트워크 경로상 가까운 DNS 서버가 응답하게 된다.
왜 이런 구조를 사용하냐면 root DNS에 하위 DNS 서버들이 계층적으로 쌓여있는 기존 구조에서는 네트워크 DNS DDos 공격이나 웜 공격등으로 root DNS가 마비되게 되면 전 세계 DNS가 마비되게 된다. 그래서 DNS를 적절히 분산 구성해 분산 처리 및 가까운 거리로 인한 네트워크 지연 감소 등 여러 이유로 사용하고 있다고 한다.
가장 유명한 예시로는 구글의 public DNS IP 8.8.8.8 이 anycast로 구성되어 있고,
전세계 국가에 분산되어 있다고 한다.
장점
- L4/L7 로드밸런싱 장비 대신 쓰기 가능?(라우팅+서버)
- 사용자와 네트워크 적으로 가장 가까운 곳으로 안내
- L4/L7 이 대규모 트래픽 처리가 힘든데 서버로 바로 트래픽을 보내니 대규모 트래픽 처리에 용이
- 회선문제로 장애시 자동으로 다른곳으로 우회(회선 이중화 비용 절감)
- 오픈소스 -> 가격 X!
단점
- 네트워크 적으로 가장 가까운곳 !== 지리적으로 가까운곳
ISP 마다 라우팅 정책이 다르므로 제어가 힘들다.
- 라우터에서 라우팅만 하기 때문에 L4/L7에선 가능한? 서버의 상태 체크(죽었나 살았나)가 안된다는 단점