동일한 값으로 업데이트 했을 때 리렌더링 - useEffect 동작 원리

zzwwoonn·2022년 6월 25일
0

React

목록 보기
21/23

기존의 state 값이 "Origin State value" 였다고 가정했을 때 버튼과 같은 사용자의 입력(action, Event)으로 setState가 동작되어 state 값을 "Origin State value"로 업데이트 했다고 가정해보자.

분명히 state의 값은 바뀌었다 (setState 트리거, 동작) state 값이 바뀌면 해당 컴포넌트는 다시 렌더링된다. (=> 컴포넌트 리렌더링의 조건) 하지만 state의 값이 똑같은 값으로 바뀌었을 때도 해당 컴포넌트는 리렌더링 될까? 실습 코드를 짜보고 하나하나 console을 찍어가며 직접 눈으로 확인했다.

이번 웹 스터디할 때 "리액트 컴포넌트의 생명주기"라는 주제의 실습 코드로 채원이가 만들어 온 코드이다. 이 코드를 참고해서 useEffect 동작을 살펴본다.

실습 코드

// LifeCycle2.js
import React, { useEffect, useState, useRef } from 'react';

function Description2(props) {
	// Constuctor 대신
	// alert('자시기기기기기긱');
	console.log('Func - 컴포넌트 내부');
	const h1Ref = useRef();
	const [content, setContent] = useState('not Props');
	const [BGcolor, setBGColor] = useState('skyblue');

	//componentDidMount 대신
	useEffect(() => {
		console.log('Func - 컴포넌트 마운트');
	}, []);

	//componentDidUpdate & getDerivedStateFromProps 대신
	useEffect(() => {
		console.log('Before : ' + BGcolor + ' / ' + content + ' / ' + props.content);
		console.log('Func - 컴포넌트 업데이트 (Rendering 될때마다)');
	});

	useEffect(() => {
		console.log('Func - 컴포넌트 업데이트 (BGcolor 수정될때마다)');
		h1Ref.current.style.backgroundColor = BGcolor;
	}, [BGcolor]);

	useEffect(() => {
		console.log('Func - 컴포넌트 업데이트 (content 수정될때마다)');
	}, [content]);

	useEffect(() => {
		console.log('Func - 컴포넌트 업데이트 (Props 수정될때마다)');
		setContent(props.content);
	}, [props]);

	const changeColor = () => {
		if (BGcolor === 'pink') setBGColor('skyblue');
		else setBGColor('pink');
	};

	return (
		<div>
			<h1 ref={h1Ref} style={{ backgroundColor: BGcolor }} onClick={changeColor}>
				This is {content}
			</h1>
		</div>
	);
}

export const LifeCycle2 = () => {
	const [content1, setContent1] = useState(0);

	useEffect(() => {
		console.log('123');
	}, [content1]);

	const changeRealButton = () => {
		console.log('[Real Button Clicked]');
		setContent1(111111);
	};

	const changeFakeButton = () => {
		console.log('[Fake Button Clicked]');
		setContent1(0);
	};

	return (
		<div>
			<Description2 content={content1} />
			<button onClick={changeRealButton}>Real Update</button>
			<button onClick={changeFakeButton}>Fake Update</button>
		</div>
	);
};

동작 과정

제일 처음 페이지가 로드 되고나서 위와 같이 console이 찍힌다. Real Update 버튼을 누르면 다음과 같은 과정이 수행된다.

1

Real Update 버튼을 클릭 함과 동시에 onClick 이벤트로 changeRealButton 함수 호출

2

console.log('[Real Button Clicked]'); 

코드가 실행되어 콘솔이 찍히고

3

setContent1(111111);

코드가 실행되어 state : content1 의 값이 0에서 111111로 바뀐다.

content1의 값이 바뀌고 여기서(LifeCycle2) 할 작업은 끝

<Description2 content={content1} /> 

코드를 수행한다.

4

state 값의 변경은 컴포넌트의 리렌더링 조건에 해당하므로 컴포넌트 리렌더링

5

제일 위에서부터 "Func - 컴포넌트 내부" console이 찍히고

6

useEffect(() => {
	console.log('Before : ' + BGcolor + ' / ' + content + ' / ' + props.content);
	console.log('Func - 컴포넌트 업데이트 (Rendering 될때마다)');
});

useEffect의 조건이 아무것도 없으므로 컴포넌트가 렌더링 될 때마다 위의 코드가 실행될 것이다.

7

버튼을 누르기 전에

		<Description2 content={content1} />
        

위의 코드에서 넘겨주는 props : content1 은 0 이었는데 state가 바뀌면서 content1 에서 props로 넘겨주는 값이 11111 로 바뀐다.

8

useEffect(() => {
	console.log('Func - 컴포넌트 업데이트 (Props 수정될때마다)');
	setContent(props.content);
}, [props]);

props의 값이 바뀌었으므로 콘솔이 찍히고 해당 컴포넌트에서 content 의 값이 "not Props" 로 바뀐다.

9

해당 컴포넌트의 state => content 값이 바뀌었으므로 다시 컴포넌트 리렌더링

10

useEffect(() => {
	console.log('Func - 컴포넌트 업데이트 (content 수정될때마다)');
}, [content]);

state : content 의 값 변경에 따른 useEffect 동작


이 상태에서 만약 Real Update 버튼을 한번 더 누르면 콘솔이 어떻게 찍힐까?

두 가지 경우를 생각해볼 수 있다.

첫 번째는 state의 값이 11111 에서 11111 으로 바뀌는데 , 이는 똑같은 값이므로 useEffect 입장에서 state가 바뀌지 않았다고 판단하게 되고 그럼 위에 엄청나게 나왔던 console 들은 전부 출력되지 않을 것이다.

두 번째는 내가 그럴거라고 유추했던 경우인데 11111에서 11111으로 바뀌어도 값이 바뀌었다고 봐야 하므로 console 이 그대로 찍혀야된다.

결과는?

버튼을 아무리 눌러도 "Real Button Clicked" 라는 콘솔만 찍힌다. 이는 버튼에 걸려있는 onClick 함수이고 그 뒤의 동작들은 전혀 실행하지 않는다.

정확한 정답은 리액트 공식문서에서 찾아볼 수 있었다. 사실 정확히 동일한 값으로 바뀌는데도 리렌더링을 계속 해주면? 리액트 엔진에 엄청난 오버헤드가 걸릴 것이다.

업데이트 함수가 현재 상태와 정확히 동일한 값을 반환하면 후속 재렌더링은 완전히 건너뜁니다.

- 리액트 공식문서

0개의 댓글