- Side Effect란, React 컴포넌트가 화면에 렌더링된 이후 비동기로 처리되어야 하는 부수적인 효과들을 말한다.
- 함수 내에서 어떤 구현이 함수 외부에 영향을 끼치는 경우, 해당 함수는 Side Effect가 있다고 이야기한다.
- React 컴포넌트 내에서 fetch를 사용하여 API를 가져오거나, 이벤트를 활용해 DOM을 조작할 때 Side Effect가 발생한다.
- 아래 코드에서는 전역변수
foo
를 함수bar()
가 수정하고 있다. 그러므로bar()
는 Side Effect를 발생시킨다.let foo = 'hello'; function bar() { foo = 'world'; } bar();
function upper(str) {
// toUpperCase 메소드는 원본을 수정하지 않음 (Immutable)
return str.toUpperCase();
}
upper('hello') // 'HELLO'
function SingleTweet({ writer, body, createdAt }) {
return <div>
<div>{writer}</div>
<div>{createdAt}</div>
<div>{body}</div>
</div>
}
하지만, React에서 AJAX 요청이 필요하거나 LocalStorage, 타이머와 같은 API를 사용하는 경우 Side Effect가 된다.
React 컴포넌트에서의 Side Effect가 발생하는 경우
타이머 사용 (setTimeout)
데이터 가져오기 (fetch API, localStorage)
이 때문에 React에서 Side Effect를 다루기 위한 Hook인 Effect Hook을 제공한다.
useEffect
는 컴포넌트 내에서 Side Effect를 실행할 수 있게 하는 Hook이다.useEffect
의 첫 번째 인자는 함수이다. 해당 함수 내에서 Side Effect를 실행한다.- 매번 새롭게 컴포넌트가 렌더링 될 때 Effect Hook이 실행된다.
👉 컴포넌트 생성 후 처음 화면에 렌더링(표시)
👉 컴포넌트에 새로운 props가 전달되며 렌더링
👉 컴포넌트에 상태(state)가 바뀌며 렌더링
useEffect
의 두 번째 인자는 배열이다. 이 배열은 조건을 담고있으며, 조건은 boolean 형태가 아닌 어떤 값의 변경이 일어날 때를 의미한다.
두 번째 배열을 빈 배열 []
로 둘 경우
useEffect(함수, [])
👉 컴포넌트가 처음 생성될 때만 effect 함수가 실행된다.
👉 이 방법은 대표적으로, 맨 처음 외부 API를 통해 리소스를 받아오고 더 이상 API 호출이 필요하지 않을 때에 사용할 수 있다.
아무것도 넣지 않을 경우 (기본 형태)
useEffect(함수)
👉 컴포넌트가 처음 생성되거나, props나 state가 업데이트될 때 실행
- 컴포넌트 내에서 필터링: 전체 목록 데이터를 불러오고, 목록을 검색어로 filter 하는 방법
- 처음에 한 번만 외부 API로부터 명언 목록을 받아오고, filter 함수를 이용
import { useEffect, useState } from "react"; import { getProverbs } from "./storageUtil"; export default function App() { const [proverbs, setProverbs] = useState([]); const [filter, setFilter] = useState(""); useEffect(() => { console.log("언제 effect 함수가 불릴까???"); const result = getProverbs(); setProverbs(result); }, []); const handleChange = (e) => { setFilter(e.target.value); }; return ( <div className="App"> <span>필터</span> <input type="text" value={filter} onChange={handleChange} /> <ul> {proverbs.filter((prvb) => { return prvb.toLowerCase().includes(filter.toLowerCase()); }).map((prvb, i) => ( <Proverb saying={prvb} key={i} /> ))} </ul> </div> ); } function Proverb({ saying }) { return <li>{saying}</li>; }
- 컴포넌트 외부에서 필터링: 컴포넌트 외부로 API 요청을 할 때, 필터링 한 결과를 받아오는 방법
- 검색어가 바뀔 때마다, 외부 API를 호출
import { useEffect, useState } from "react"; import { getProverbs } from "./storageUtil"; export default function App() { const [proverbs, setProverbs] = useState([]); const [filter, setFilter] = useState(""); const [count, setCount] = useState(0); useEffect(() => { console.log("언제 effect 함수가 불릴까???"); const result = getProverbs(filter); setProverbs(result); }, [filter]); const handleChange = (e) => { setFilter(e.target.value); }; const handleCounterClick = () => { setCount(count + 1); }; return ( <div className="App"> 필터 <input type="text" value={filter} onChange={handleChange} /> <ul> {proverbs.map((prvb, i) => ( <Proverb saying={prvb} key={i} /> ))} </ul> <button onClick={handleCounterClick}>카운터 값: {count}</button> </div> ); } function Proverb({ saying }) { return <li>{saying}</li>; }
컴포넌트 내에서 필터링과 컴포넌트 외부에서 필터링의 차이점
장점 | 단점 | |
---|---|---|
컴포넌트 내부에서 처리 | HTTP 요청의 빈도를 줄일 수 있다 | 브라우저(클라이언트)의 메모리 상에 많은 데이터를 갖게 되므로, 클라이언트의 부담이 늘어난다 |
컴포넌트 외부에서 처리 | 클라이언트가 필터링 구현을 생각하지 않아도 된다 | 빈번한 HTTP 요청이 일어나게 되며, 서버가 필터링을 처리하므로 서버가 부담을 가져간다 |