드디어 밀린 블로그를 쓸 떄가 왔다.
타이밍 좋게도, 어려웠던 단원들을 복습 블로깅 하는 그룹 활동이 시작되었다.
그룹 활동과 밀린 블로그 쓰기, 그리고 복습까지 무려 세마리 토끼를 잡을 수 있는 시간!!
1. Side Effect
let num = 1
console.log(num)
function sum(){
num += 1
}
sum()
console.log(num)
위 코드를 실행시켜보자.
정수 num이 sum() 함수로 인해 1에서 2로 바뀌어 두번의 console.log에서 출력되는 값이 다른 것을 볼 수 있다.
이처럼 함수 외부의 값이 함수 내의 어떤 구현으로 인해 영향을 받는 것을 'Side Effect(부수 효과)'라고 한다.
sum() 함수도 num 값을 변화시켰기 때문에 Side Effect를 발생시킨다.
이러한 side effect를 발생시키지 않는 함수는 '순수 함수'라고 한다.
순수 함수란, 오직 함수의 입력만이 함수의 결과에 영향을 주고, 입력으로 전달된 값을 수정하지 않는 함수를 의미한다.
function pure(num){
return num * 3
}
pure(1) //3
pure(2) //6
pure(3) //9
순수 함수는 하나의 input에 대해 하나의 output만을 출력한다. 즉, 같은 전달 인자에 대해서는 늘 같은 값만 출력한다는 것이다. 그래서 순수함수는 '예측 가능한 함수'이기도 하다.
위 코드에서 pure 함수에는 어떤 값이 들어가던, 3을 곱한 값이 출력된다. num이 1이라고 해서 어떤 경우에는 출력이 3, 어떤 경우에는 6, 어떤 경우에는 999로 바뀌는 것이 아니라, 무조건 3만 출력하는 것이다.
따라서 pure는 순수 함수라고 할 수 있다.
function Component({name}){
return (
<div>
<h1>Hi, {name}</h1>
</div>
)
}
React의 함수 컴포넌트는 props를 입력하면 JSX Element가 출력된다. 여기에는 그 어떤 Side Effect도 없으며, 순수 함수로 작동한다.
하지만 보통 React 애플리케이션을 작성할 때에는, AJAX 요청이 필요하거나, LocalStorage 등의 API를 사용하는 경우가 발생할 수 있다. 이러한 행동들은 React의 입장에서는 전부 Side Effect 이기 떄문에, React는 Side Effect를 다루기 위한 Hook인 Effect Hook을 제공한다.
2. useEffect
만약, 어떤 상태가 바뀔 때 마다 컴포넌트들이 전부 렌더링 된다고 생각해보자.
네이버에 검색을 하는데 검색창에 한글자 칠때마다 계속해서 페이지가 새로고침 되는 것이다.
한글자 한글자 칠때마다 새로고침이 되고, 모든 컴포넌트들이 렌더링 되기를 기다리는 것은 매우매우 어렵고 화가 나는 일이다.
Side Effect는 다음과 같은 상황에 발생한다
- 컴포넌트 생성
- 컴포넌트에 새로운 props 전달
- 컴포넌트에 상태(state) 변경
한 페이지에 존재하는 컴포넌트는 적게는 수개에서 많게는 수십개가 될 수 있고, state나 props는 그 이상이 될 수 있다.
하지만 이 수많은 컴포넌트, props, state들이 바뀔 때 마다 화면을 렌더링 하는 것은 시간적으로나 메모리적으로나 매우 비효율적인 작업일 것이다.
useEffect는 이러한 불편함을 방지하기 위해, 특정 조건에서만 Side Effect를 실행하게 해주는 Hook이다.
useEffect는 컴포넌트가 렌더링 될 때 마다 Side Effect를 실행시킨다는 것은 같지만, Side Effect가 발생하는 조건과, 이 조건이 만족되었을 때 실행될 Side Effect를 따로 설정할 수 있다.
A. Side Effect 실행 함수
Side Effect는 함수 내에서 구현할 수 있다.
딱히 어려운 내용은 없고, 고차함수를 사용하듯 useEffect Hook 내의 첫 인자에 함수를 작성해주면 된다.
input 내에 타자를 치거나 버튼을 클릭할 때 마다 Side Effect가 발생하는 프로그램을 만들어 보았다.
import { useState, useEffect } from 'react';
function App() {
let [type, setType] = useState(0)
let [click, setClick] = useState(0)
useEffect(()=>{
console.log('Side Effect 발생!')
})
function countType(){
setType(type+1)
}
function countClick(){
setClick(click+1)
}
return <div>
<input type='text' onChange={countType}></input>
<h2>입력한 타자의 개수 : {type}</h2>
<button onClick={countClick}>클릭하세요!</button>
<h2>클릭 횟수 : {click}</h2>
</div>
}
export default App;
이 경우, 화면이 새롭게 렌더링 될 때 마다 Side Effect가 발생한다.
맨 처음 입력이나 클릭하기 전에 이미 Side Effect가 발생해 있는데, 이는 '컴포넌트가 렌더링될 때 실행된 Side Effect'이다.
참고로, 2번 발생하는 이유는 Strict Mode 때문이다. 자세한 내용은 검색을,.,.,.,.,.,
여튼, 컴포넌트가 렌더링될 때 한번, 그리고 입력할 때(=state인 type이 바뀔 때)와 클릭할 때(=state인 click이 바뀔 때)마다 Side Effect가 일어난다.
이처럼 컴포넌트가 렌더링될 때나, state, props가 바뀔 때 마다 실행하고 싶은 Side Effect를 함수를 통해 설정해줄 수 있다.
B. Side Effect가 발생하는 조건
그렇다면, 이번에는 Side Effect를 원하는 시기에만 발생시킬 수 있게 만들어 주어야 한다.
이는 useEffect의 두번째 인자에서 설정할 수 있다.
useEffect의 두번째 인자에는 배열이 들어간다. 이 배열을 종속성 배열(Dependency Array)라고 하는데, 이 배열 안에 Side Effect를 발생시키고자 하는 state나 props를 넣어주면 된다.
그런데, props는 '전달되는 값이 바뀌지 않는 한 계속 같은 값이 전달된다'. 즉, 수천 수만번의 상호작용이 일어나도, props로 전달되는 값이 변하지 않는다면 props 때문에 새로 렌더링이 될 일은 없다.
따라서, props가 변하는 경우 = state가 props로 전달되는 경우이므로, 종속성 배열에는 보통 state가 들어가게 된다.
위 코드를 다음과 같이 고쳐보자
useEffect(()=>{
console.log('Side Effect 발생!')
}, [click])
종속성 배열에 click이라는 state가 들어가 있다.
이말인 즉슨, click이 변할 때만 Side Effect가 일어난다는 것이다!
반대로, 종속성 배열에 type을 넣으면 입력할 때만 Side Effect가 발생하고, 클릭할 때는 발생하지 않을 것이다.
종속성 배열을 비워놓으면 맨 처음 한번만 Side Effect가 일어난다.
그런데, 이미 컴포넌트가 렌더링되면서 한번 일어나기 때문에, state들은 더이상 Side Effect를 발생시키지 않는다.
반면, 종속성 배열을 인자로 전달하지 않을 경우 모든 state에 대해 Side Effect들이 발생한다.
아직도 이해가 잘 안된다면, 쉽게 그림으로 알아보자
가게는 useEffect, 손님은 state, 커피를 파는 것을 Side Effect라고 생각하면 되겠다.
I. 종속성 배열에 특정 state가 있을 때
II. 종속성 배열이 빈 배열일 때
III. 종속성 배열이 없을 때
'Frontend Study' 카테고리의 다른 글
[FE_Bootcamp] 31일차_클라이언트-서버 통신 (0) | 2023.04.24 |
---|---|
[FE_Bootcamp] 46일차_Component Driven Development (0) | 2023.04.20 |
[FE_Bootcamp] 44일차_UI와 UX (0) | 2023.04.13 |
[야간자율학습반 ] 재귀 (0) | 2023.04.12 |
[FE_Bootcamp] 42일차_재귀 (0) | 2023.04.11 |