함수 내에서 어떤 구현이 함수 외부에 영향을 끼치는 경우 해당 함수는 Side Effect
가 있다고 이야기한다. React에서는 컴포넌트 내에서 fetch를 사용해 API 정보를 가져오거나 이벤트를 활용해 DOM 직접 조작할 때 Side Effect가 발생했다고 말한다.
다음은, 전역 변수 foo를 bar라는 함수가 수정하는 예제입니다.
let foo = 'hello';
function bar() {
foo = 'world';
}
bar(); // bar는 Side Effect를 발생시킵니다!
Pure Function (순수 함수)
순수 함수란, 오직 함수의 입력만이 함수의 결과에 영향을 주는 함수를 의미합니다. 함수의 입력이 아닌 다른 값이 함수의 결과에 영향을 미치는 경우, 순수 함수라고 부를 수 없습니다. 또한 순수 함수는, 입력으로 전달된 값을 수정하지 않습니다.
function upper(str) {
return str.toUpperCase(); // toUpperCase 메소드는 원본을 수정하지 않습니다 (Immutable)
}
upper('hello') // 'HELLO'
순수 함수에는 네트워크 요청과 같은 Side Effect가 없습니다. 순수 함수의 특징 중 하나는, 어떠한 전달 인자가 주어질 경우, 항상 똑같은 값이 리턴됨을 보장합니다. 그래서 예측 가능한 함수이기도 합니다.
React의 함수 컴포넌트
우리가 앞서 배운 React의 함수 컴포넌트는, props가 입력으로, JSX Element가 출력으로 나갑니다. 여기에는 그 어떤 Side Effect도 없으며, 순수 함수로 작동합니다.
function SingleTweet({ writer, body, createdAt }) {
return <div>
<div>{writer}</div>
<div>{createdAt}</div>
<div>{body}</div>
</div>
}
하지만 보통 React 애플리케이션을 작성할 때에는, AJAX 요청이 필요하거나, LocalStorage 또는 타이머와 같은 React와 상관없는 API를 사용하는 경우가 발생할 수 있습니다. 이는 React의 입장에서는 전부 Side Effect 입니다. React는 Side Effect를 다루기 위한 Hook인 Effect Hook을 제공합니다.
만약 어떤 함수가 서버에 네트워크 요청을 보낸다면 이로 인해 서버의 데이터에 Side Effect를 일으킬 수 있고, 이에 따라 해당 함수는 순수 함수가 아닙니다.
useEffect는 컴포넌트 내에서 Side effect를 실행할 수 있게 하는 Hook 입니다. 이 컴포넌트에서 실행하는 Side effect는 브라우저 API를 이용하여, 타이틀을 변경하는 것입니다. 다음 코드를 확인해 보세요.
API
useEffect(함수)
useEffect의 첫 번째 인자는 함수입니다. 해당 함수 내에서 side effect를 실행하면 됩니다. 이 함수는 다음과 같은 조건에서 실행됩니다.
컴포넌트 생성 후 처음 화면에 렌더링(표시)
컴포넌트에 새로운 props가 전달되며 렌더링
컴포넌트에 상태(state)가 바뀌며 렌더링
이와 같이 매번 새롭게 컴포넌트가 렌더링 될 때 Effect Hook이 실행됩니다.
Hook을 쓸 때 주의할 점
최상위에서만 Hook을 호출합니다.
React 함수 내에서 Hook을 호출합니다.
조건부 effect 발생 (dependency array)
useEffect의 두 번째 인자는 배열입니다. 이 배열은 조건을 담고 있습니다. 여기서 조건은 boolean 형태의 표현식이 아닌, 어떤 값의 변경이 일어날 때를 의미합니다. 따라서, 해당 배열엔 어떤 값의 목록이 들어갑니다. 이 배열을 특별히 종속성 배열이라고 부릅니다.
이 예제를 열어보고, 개발자 콘솔의 값을 확인하세요. 여기에는 다음과 같은 세 상태가 존재합니다.
한편, 카운트를 올리는 버튼은 컴포넌트의 상태가 바뀌고 업데이트되지만, 아무리 버튼을 눌러도 effect 함수는 실행되지 않습니다. 왜냐하면, 종속성 배열에는 filter만 존재하고, count는 존재하지 않기 때문입니다.
질문
카운트 버튼을 눌렀을 때에도 effect 함수를 실행시키려면 어떻게 해야 하나요?
useEffect(함수, [종속성1, 종속성2, ...])
useEffect의 두 번째 인자는 종속성 배열입니다. 배열 내의 종속성1, 또는 종속성2의 값이 변할 때, 첫 번째 인자의 함수가 실행됩니다.
배열 내의 어떤 값이 변할 때에만, (effect가 발생하는) 함수가 실행됩니다.
단 한 번만 실행되는 Effect 함수
만일 종속성 목록에 아무런 종속성도 없다면 어떤 일이 발생할까요? 달리 말해, 두 번째 배열을 빈 배열[]로 둘 경우에는 무슨 일이 발생할까요? 두 번째 인자를 아예 안 넘기는 것과 어떻게 다를까요?
- 빈 배열 넣기
useEffect(함수, [])- 아무것도 넣지 않기 (기본 형태)
useEffect(함수)
(2번) 기본 형태의 useEffect 는 컴포넌트가 처음 생성되거나, props가 업데이트되거나, 상태(state)가 업데이트될 때 effect 함수가 실행됨을 앞서 배웠습니다.
반면에 (1번) 빈 배열을 useEffect의 두 번째 인자로 사용하면, 이때에는 컴포넌트가 처음 생성될 때만 effect 함수가 실행됩니다. 이것이 언제 필요할까요? 대표적으로 처음 단 한 번, 외부 API를 통해 리소스를 받아오고 더 이상 API 호출이 필요하지 않을 때에 사용할 수 있습니다.