효뚜르팝의 Dev log
[React 공식문서로 공부하기2] Adding Interactivity 상호작용 추가하기 본문
리액트 공식문서를 읽고 정리한 글입니다.
Adding Interactivity 상호작용 추가하기
https://react-ko.dev/learn/adding-interactivity
1. Responding to Events
2. State : A components' memory
- 지역 변수는 렌더링 간에 유지되지 않는다.
- 지역 변수를 변경해도 렌더링을 발동시키지 않는다.
- State is isolated and private.
- state 변수는 컴포넌트의 리렌더링 사이에 정보를 유지하는 데만 필요하다. 단일 이벤트 핸들러 내에서는 일반 변수로도 충분하기 /대문에 일반 변수가 잘 작동할 때는 state 변수를 도입할 필요가 없다.
- ex) setName(prompt('What is your name?')); // 불필요함
- ex) setName(prompt('What is your name?')); // 불필요함
3. Render and Commit
리액트 렌더링 단계
- 렌더링 촉발
- 컴포넌트 렌더링
- 첫 렌더링에서 React는 루트 컴포넌트를 호출합니다.
- 이후 렌더링에서 React는 state 업데이트에 의해 렌더링이 발동된 함수 컴포넌트를 호출합니다.
- DOM에 커밋
- React는 렌더링 간에 차이가 있는 경우에만 DOM 노드를 변경
4. State as a Snapshot
- "렌더링"이란 React가 컴포넌트 즉 함수를 호출한다는 뜻. 해당 함수에서 반환하는 JSX는 시간상 UI의 스냅샷. prop, 이벤트 핸들러, 로컬 변수는 모두 렌더링 당시의 state를 사용해 계산이 된다.
- React가 함수 호출 -> 스냅샷 계산 -> DOM 트리 업데이트
- 사용자가 상호작용한 시점에 state 스냅샷을 사용하는 것은 이미 예약이 되어있다.
ex) 아래의 예시에서 alert에서 number는 0으로 노출이된다. why? 이벤트가 발생했을 때의 스냅샷으로 state값을 보여주기 때문
import { useState } from 'react';
export default function Counter() {
const [number, setNumber] = useState(0);
return (
<>
<h1>{number}</h1>
<button onClick={() => {
setNumber(number + 5);
setTimeout(() => {
alert(number);
}, 3000);
}}>+5</button>
</>
)
}
-> state 변수의 값은 이벤트 핸들러의 코드가 비동기적이더라도 렌더링 내에서 절대 변경되지 않음. state 값은 컴포넌트를 호출해 React가 UI의 스냅샷을 찍을 때 고정된 값.
5. Queueing a Series of State Updates
- state 변수를 설정하면 다음 렌더링이 큐(대기열, queue)에 들어감. 그러나 경우에 따라 다음 렌더링을 큐에 넣기 전에 값에 대해 여러 작업을 수행하고 싶을 때 사용하는 것이 -> "batching" (일괄 처리)
- React는 state 업데이트를 하기 전에 이벤트 핸들러의 모든 코드가 실행될 때까지 기다린다.
- React는 클릭과 같은 여러 의도적인 이벤트에 대해 일괄 처리하지 않으며, 각 클릭은 개별적으로 처리됨.
- n => n + 1 // 큐의 이전 state를 기반으로 다음 state를 계산하는 함수, 업데이터 함수(updater function)이라고 부름
- 이벤트 핸들러가 완료되면 React는 리렌더링을 실행함. 리렌더링을 하는 동안 React는 큐를 처리함. 업데이터 함수는 렌더링 중에 실행되므로, 업데이터 함수는 순수해야 하며 결과만 반환해야 함.
export default function Counter() {
const [number, setNumber] = useState(0);
return (
<>
<h1>{number}</h1>
<button onClick={() => {
setNumber(number + 5); // React는 5로 바꾸기를 큐에 추가
setNumber(n => n + 1); // n => n + 1 이라는 업데이터 함수를 큐에 추가
setNumber(42); // 42로 바꾸기를 큐에 추가
}}>Increase the number</button>
</>
)
}
// 다음 렌더링 동안, state 큐를 순회함
// React는 42를 최종 결과로 저장하고 UseState에서 반환함
Naming Convention
업데이터 함수 인수의 이름은 해당 state 변수의 첫 글자로 지정하는 것이 일반적임. 좀 더 자세한 코드를 선호하는 경우 state 변수 이름 반복 또는 접두사 prev를 사용하는 것이 일반적인 규칙.
setLastName(ln => ln.reverse());
6. Updating Objects in State
- mutation(변이) : 객체 자체의 내용을 변경하는 것
- React state의 객체는 기술적으로는 변이할 수 있지만, 숫자, boolean, 문자열과 같이 불변하는 것처럼 취급해야함. 객체를 직접 변이하는 대신 항상 교체해야 함.
-> state에 넣는 모든 JavaScript 객체를 읽기 전용으로 취급해야 함.
아래 예시와 같이 객체 내용을 변경하기 위해서는 새 객체를 생성하고 state 설정자 함수에 전달을 해야 리렌더링이 발생함.
import { useState } from 'react';
export default function MovingDot() {
const [position, setPosition] = useState({
x: 0,
y: 0
});
return (
<div
onPointerMove={e => {
setPosition({
x: e.clientX,
y: e.clientY
});
}}
</div>
);
}
참고 사항)
변이는 이미 state가 있는 기존 객체를 변경할 때만 문제가 됨. 방금 생성한 객체를 변경해도 다른 코드가 아직 참조하지 않으므로 괜찮음 .
아래의 경우는 지역 변이로 문제가 되지 않음.
const nextPosition = {};
nextPosition.x = e.clientX;
nextPosition.y = e.clientY;
setPosition(nextPosition);
- 모든 속성을 개별적으로 복사할 필요가 없도록 `...`객체 전개 구문을 사용할 수 있음.
- 기존의 객체를 복사해와서 변이를 하는 게 더 좋은 이유?
-> 객체를 복사해오면 기존 객체와 참조값이 달라지기 때문에 객체 내부까지 값을 계산하면서 다른 객체인지 확인하지 않아도 된다는 점에서 메모리가 절약됨 (특히나 중첩된 객체의 경우 가장 하단의 필드까지 확인하지 않아도 된다는 이점이 있음)
7. Updating Arrays in State
- 객체와 마찬가지로 React state의 배열은 읽기 전용으로 취급해야 함. (JavaScript에서 배열은 객체의 또 다른 종류일 뿐이기 때문)
- 배열을 변이하는 대신 배열의 새로운 버전을 생성하고 state를 업데이트 하기 (배열 전개 구문을 사용하여)
- filter, map 을 사용하여 필터링되거나 변형된 항목으로 새 배열을 만들 수 있다.
추가로 알아본 거
- react 18에서 새로 추가된 Automatic Batching 이라는 게 있다.
Automatic Batching은 Batching을 자동으로 처리해주는 기능이다. 이전 Batching 과 다르게, 어디에서 상태가 변경되던지 상관없이 Batching 이 일어난다. (promises, setTimeout, native event handlers 등에서도 모두 Batching 이 일어남)
참고하면 좋은 글)
https://react.dev/blog/2022/03/29/react-v18
https://hwani.dev/react-automatic-batching/
- setState는 비동기적로 동작한다.
setState가 가끔 의도한 대로 동작하지 않을 때가 있다. 이는 setState가 비동기적으로 동작하기 때문이다.
setState에서 상태를 변경할 때마다 컴포넌트가 재렌더링 되기 때문에 컴포넌트의 상태값이 많을 때 이 상태값들이 바뀔 때마다 재렌더링이 되면 성능상 이슈가 생길 수 있기 때문이라고 한다.
참고하면 좋은 글)
https://codingapple.com/unit/react-setstate-async-problems/
https://www.linkedin.com/pulse/provide-callback-usestate-hook-like-setstate-saransh-kataria/
'TIL' 카테고리의 다른 글
| [React 공식문서로 공부하기4] Escape Hatches 탈출구 (5) | 2024.03.04 |
|---|---|
| [React 공식문서로 공부하기3] Managing State (1) | 2024.02.25 |
| [React 공식문서로 공부하기] Describe the UI (0) | 2024.02.18 |
| PoC를 진행할 때 유의할 점에 대해서 (3) | 2024.02.04 |
| 디자인 시스템 구축을 위해 Shadcn UI와 Radix Theme PoC 진행해보기 (2) | 2024.01.21 |