[React] side effect를 편리하고 안전하게 발생시킬 수 있게 도와주는 "useEffect"

MOONJUNG·2022년 9월 4일
0

React

목록 보기
1/10
post-thumbnail

프로그래밍에서 Side Effect란?

함수가 함수 내부의 값 외에 외부의 값을 읽어오거나, 수정하는 행위

Side Effect의 예시

1. side effect가 있다

외부의 상태를 읽어올 때

    const num = 1;
    
    const sum = (x) => {
      return x + num;
    };

함수가 함수 내부의 값(local state)를 제외한 나머지 값(non local state)들을 읽어올 때 side effect가 있다고 말한다.

2. side effect가 발생했다

외부의 상태를 변경 시킬 때
함수가 함수 내부에 있는 값이 아닌, 외부의 값을 변경시킬 때 side effect가 발생했다고 말한다.

1. 외부의 변수 값을 변경했을 때

    let num;
    
    const sum = (x) => {
      num = x + 1;
    };

2. DOM 조작

    const changeTitle = (newTitle) => {
      const title = document.getElementById('title');
    
      title.innerText = newTitle;
    };

3. console에 특정문자 출력

    const printNum = (x) => {
      console.log(x);
    };

프로그래밍에서 side effect는 기피해야 하는 대상일까?

Yes → 동작 결과를 예측하기 쉽지 않고 유지보수가 어렵기 때문이다.

그러나, 프로그래밍에서 외부의 값을 읽어오거나 변경하는 일은 완전히 배제할 수는 없다. 결론은 개발자가 side effect 최소화할 수 있게 설계해야한다.

함수 컴포넌트 Side Effect 예시

1. Data Fetching

프론트엔드 - 복잡한 UI를 구성, 변화시키는 데에 초점
백엔드 - 데이터를 저장하고 처리, 가공

⇒ 프론트엔드가 백엔드 API를 통해서 기존에 저장된 데이터를 가져오는 일은 반드시 발생한다!

2. DOM 조작

대부분 선언적 개발을 한다.

⇒ React에서 DOM의 조작을 대신해주고 개발자는 UI와 핵심 로직에만 신경 쓴다. DOM에 직접 접근할 일이 많지 않고, 직접 조작하는 일은 권장하지 않는다. 단, DOM 직접 조작해야만 하는 특정 상황은 제외시킨다.

3. 구독(Subscribe)

어떤 것의 변화를 계속해서 지켜보고 변화가 발생하면 특정한 액션을 취하는 것

시간의 변화에 따른 동작 이행

  • setTimeout : 일정 시간이 지나면 특정 동작을 수행
  • setInterval : 일정 시간마다 특정 동작을 수행

Side Effect의 올바른 발생 시점

  1. 렌더링을 Blocking 하지 않기 위해서

    렌더링이 모두 다 완료되고 난 후 실행할 수 있어야 한다.


  2. 매 렌더링마다 실행되는 것이 아니라

    내가 원할 때만 조건부로 실행할 수 있어야 한다.

useEffect

React에서 side effect를 편리하고 안전하게 발생시킬 수 있게 도와주는 hook

사용 방법

1. 렌더링을 blocking 하지 않고 side effect를 발생

    useEffect(콜백 함수);
  • 인자로 전달하는 콜백 함수에서 특정한 side effect를 수행시킬 수 있다

모든 렌더링이 완료된 후에 호출해준다

2. 조건부로 Side Effect 발생

    useEffect(콜백 함수, 의존성 배열);
  • 매개변수
    1. 콜백함수
      • 실행시킬 동작을 결정
    2. 의존성 배열
      • side effect의 발생 여부를 결정짓는 조건
      • 실행시킬 타이밍을 결정
import { useEffect } from 'react'

// 1. 의존성 배열이 전달되지 않았으므로 매 렌더링마다 side effect가 실행된다
useEffect(() => {
  // side effect
});

// 2. 첫 번째 렌더링 이후에 side effect를 실행하고
// 그 이후에는 value 값이 변했을 때만 실행한다.
useEffect(() => {
  // side effect
}, [value]);

// 3. 첫 번째 렌더링 이후에 side effect를 실행하고
// 그 이후에는 value1, value2 중 하나라도 변하면 side effect를 실행한다.
useEffect(() => {
  // side effect
}, [value1, value2]);

// 4. 첫 번째 렌더링 이후에만 실행되고 그 뒤에는 실행되지 않는다
// 의존성 배열이 전달은 되었지만 배열 안에 값이 아무것도 없기 때문에
// 변화를 비교할 값이 없고 따라서 첫 번째 렌더링 이후에만 실행되고 그 뒤에는 실행되지 않는다.
useEffect(() => {
  // data fetching side effect
}, []);

useEffect와 React Component가 렌더링 되는 과정

  1. Mount : 컴포넌트가 최초로 브라우저에 렌더링
  2. Side Effect : useEffect 첫 번째 인자로 넘겨준 콜백 함수가 호출
  3. Update : 컴포넌트의 state 또는 props가 변경되었을 경우 리렌더링이 발생
  4. useEffect는 두 번째 인자에 들어있는 의존성 배열을 확인

    4-1.
    만약 의존성 배열이 전달되지 않았거나
    의존성 배열 내부의 값 중 이전 렌더링과 비교했을 때
    변경된 값이 하나라도 있다면
    → 첫 번째 인자로 넘겨준 콜백 함수 호출O

    4-2.
    의존성 배열 내부의 값 중 이전 렌더링과 비교했을 때
    변경된 값이 없다면 → 콜백 함수를 호출X

    4-3. state 또는 props가 변경된다면 → 3~4번의 과정을 반복

  5. Unmount : 컴포넌트가 더 이상 필요 없어지면 화면에서 사라진다

Clean Up

왜 필요할까?

불필요하게 계속해서 side effect가 남아있다면

  • 비효율적으로 작동하거나
  • 프로그램의 동작이 의도한 대로 되지 않을 수도 있기 때문이다.

어떻게 사용할까?

useEffect에 전달한 콜백 함수에서 clean up을 하는 함수를 리턴

clean up 함수를 return만 해준다면 clean up 함수를 적절한 시점에 호출해 주는 일은 useEffect가 알아서 처리해준다.

언제 쓸까?

  1. 다음 side effect를 발생시키기 전
  2. 컴포넌트가 unmount 될 때
profile
뜨거운 열정으로 꿈을 실현하는 프론트엔드 개발자 장문정

0개의 댓글