리액트에는 Side Effect라는 말이 있다.
함수의 목적인 Input을 받아서 output을 산출하는 것 이외의 모든 행위를 의미한다.
const num = 1;
const sum = (x) => {
return x + num;
};
위에 경우는 외부요소인 num을 가져오기 때문에 side effect가 있다고 표현할 수 있다.
DOM을 조작하고, console에 특정 문자를 출력하는 행위 또한 side effect가 발생한다고 할 수 있다.
즉 정리하자면
side effect는 함수가 input을 받아서 output을 산출하는 과정에서
이러한 side effect가 있는 함수는 동작 결과를 예측하기 쉽지 않아서 주의해야 한다. 따라서 , 개발자들은 side effect를 최소화 하면서 프로그램을 설계하되, side effect가 필요한 경우에는 그것을 반드시 통제 가능하게 만들어야 한다.
리액트는 컴포넌트의 state나 props가 변하면 자동으로 해당 함수 컴포넌트를 다시 호출하면서 리렌더링을 수행해 준다.
하트 색깔을 변경하는 등 작은 UI 업데이트가 발생할 때마다 매번 모든 피드 데이터를 다 가져온다면 불필요한 동작을 계속 수행하기에 비효율적이다.
Side Effect는
리액트는 이를 useEffect라는 hook을 통해 해결한다.
useEffect(콜백 함수, 의존성 배열);
useEffect의 인자로 전달된 콜백 함수는 곧바로 호출되는 것이 아니라 모든 렌더링이 완료된 후에 호출된다. 의존성 배열은 바로 side effect의 발생 여부를 결정짓는 조건이다.
첫 번째 렌더링 이후에는 무조건 useEffect에 전달된 콜백 함수를 호출하고 다음 렌더링부터는 아래의 조건에 따라 동작한다.
의존성 배열이 전달되지 않았다면 매 렌더링마다 콜백 함수를 호출한다.
의존성 배열이 전달되었다면 의존성 배열의 값을 검사한다.
a. 의존성 배열에 있는 값 중 하나라도 이전 렌더링과 비교했을 때 달라졌다면 콜백 함수를 호출한다.
b. 의존성 배열에 있는 값이 이전 렌더링과 비교했을 때 모두 다 같다면 콜백 함수를 호출하지 않는다.
함수 컴포넌트의 렌더링과 useEffect가 발생하는 과정을 풀어서 설명하자면 아래와 같다.
컴포넌트가 렌더링 된다.
(최초로 진행되는 렌더링은 브라우저에 처음으로 이 컴포넌트가 보였다는 의미로 mount
라고 표현한다.)
useEffect 첫 번째 인자로 넘겨준 콜백 함수가 호출된다. (Side Effect)
컴포넌트의 state 또는 props가 변경되었을 경우 리렌더링이 발생한다. (update)
useEffect는 두 번째 인자에 들어있는 의존성 배열을 확인한다
컴포넌트가 더 이상 필요 없어지면 화면에서 사라진다.
(컴포넌트가 브라우저의 화면에서 사라졌다는 의미로 unmount
라고 표현한다.)
useEffect(() => {
const countTime = () => {
console.log('100ms가 지났습니다.');
};
setInterval(countTime, 100);
}, []);
위 코드와 같이, 창을 옮겼을 때도 반복되는 함수를 막기 위해 clean up이 필요하다.
useEffect(() => {
const button = document.getElementById('consoleButton');
const printConsole = () => {
console.log('button clicked');
};
button.addEventListener('click', printConsole);
// side effect를 clean up 하기 위한 함수를 선언한다.
const removeEventListener = () => {
button.removeEventListener('click', printConsole);
};
// clean up 함수를 return 한다.
return removeEventListener;
});
위와 같이 return을 사용해주면 된다.
clean 합수는 두가지 경우에 호출해 준다.
1. 다음 side effect를 발생시키기 전
2. 컴포넌트가 unmount 될 때