Hyunjung Im
Frontend Developer
2023-01-13
함수형 프로그래밍
함수형 컴포넌트 사용 전
https://blog.logrocket.com/optimizing-performance-react-application/ https://beta.reactjs.org/learn/queueing-a-series-of-state-updates#react-batches-state-updates https://yceffort.kr/2022/04/deep-dive-in-react-rendering
리액트는 값 UI이다. UI가 문자열이나 배열과 마찬가지로 “값”이라는 것
가상 DOM 개념을 사용하여 실제 DOM 조작하는 데 비용 많이 듦 -> 다시 렌더링하는 성능 비용을 최소화
js가 컴파일되고 배포 준비가 되는 순간에 React.createElement()를 호출하여 변환된다. 결과물을 수집하고 리액트는 새로운 오브젝트 트리 (가상돔)와 비교하며 모든 변경 사항을 수집한다. 이렇게 비교하고 계산하는 과정을 리액트에서는 reconciliation 이라고 한다. 그런 다음 리액트는 계산된 모든 변경 사항을 하나의 동기 시퀀스로 DOM에 적용한다.
리액트는 커밋 단계에서 DOM을 업데이트한 후 요청된 DOM 요소 및 컴포넌트 인스턴스를 가리키도록 모든 참조를 업데이트한다. 그리고 useLayoutEffect 훅을 동기적으로 실행한다. 그런 다음 리액트는 짧은 시간 제한을 설정하고 이 시간이 만료되면 useEffect 훅을 실행한다.
렌더링은 DOM 업데이트와 같지 않으며 결과적으로 어떠한 가시적인 변경도 일어나지 않고 컴포넌트가 리렌더링될 수 있다.
Render phase 사이드 이펙트가 없는 순수함을 가진다. 일시 중지되거나 리액트에 의해 재시작 또는 중단될 수 있다.
Commit phase DOM과 함께 작동할 수 있다. 사이드 이펙트를 실행하고 스케줄을 업데이트한다.
Cleanup phase 컴포넌트가 제거되기 전에 실행해서 메모리 누수를 막는다.
리액트의 기본 동작은 상위 컴포넌트가 렌더링될 때 리액트가 해당 컴포넌트 내부의 모든 하위 컴포넌트를 순환하며 렌더링한다. 즉 컴포넌트를 렌더링하면 기본적으로 모든 하위 컴포넌트가 렌더링 된다.
기억할 것은 렌더링은 나쁜 게 아님. 이는 리액트가 실제로 DOM을 변경해야 하는지 여부를 아는 방법일 뿐.
렌더링이 ‘순수’해야 하며 어떠한 사이드 이펙트도 없어야 한다.
렌더 로직은 다음을 수행해선 안된다.
렌더 로직은 다음을 수행할 수 있다.
setState를 사용할 때 state를 바로 수정하는 방법은 함수형 프로그래밍에 맞지 않다. React가 제공하는 한 가지 개선 사항은 업데이터 함수에 콜백을 전달하는 것입니다. 이 콜백에서 이전 버전의 상태에 액세스할 수 있으며 여기에서 상태 값을 업데이트할 수 있습니다.
export default function App() {
const [test, setTest] = useState(0);
const [test2, setTest2] = useState(0);
const [toggle, setToggle] = useState(true);
// 버튼을 클릭할 때마다 실행되는 두 개의 useEffect가 있습니다.
// 1번 문제
useEffect(() => {
setTest(5);
setTest(test + 1);
}, [toggle]);
// 2번 문제
useEffect(() => {
setTest2(5);
setTest2((prev) => prev + 1);
}, [toggle]);
console.log({
test1: test, // 1. 버튼을 누를 때마다 어떤 값이 찍힐까요?
test2: test2, // 2. 버튼을 누를 때마다 어떤 값이 찍힐까요?
});
return (
<div className="App">
<button onClick={() => setToggle(!toggle)}>test</button>
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
</div>
);
}