Post

Side-Effect에 대해 알아보자

안녕하세요! 오늘은 자바스크립트와 리액트 애플리케이션에서 중요한 개념 중 하나인 사이드 이펙트(Side Effect)에 대해 알아보겠습니다. 사이드 이펙트를 이해하면 코드의 예측 가능성과 유지보수성을 높일 수 있습니다. 그럼 바로 시작하겠습니다.

Side-Effect란 무엇인가?

정의

사이드 이펙트는 함수나 표현식이 실행될 때, 함수의 반환값 이외에 외부 상태나 시스템에 영향을 미치는 모든 작업을 의미합니다. 예를 들어, 데이터베이스에 데이터를 저장하거나, 콘솔에 로그를 출력하거나, 전역 변수를 변경하는 것 등이 사이드 이펙트에 해당합니다.

예제

1
2
3
4
5
6
7
8
9
let globalVar = 0;

function add(a, b) {
    globalVar = a + b; // 사이드 이펙트: 외부 상태(globalVar)를 변경함
    return globalVar;
}

console.log(add(2, 3)); // 5
console.log(globalVar); // 5 (함수 실행으로 인해 globalVar가 변경됨)

위 예제에서 add 함수는 매개변수 ab의 합을 반환할 뿐만 아니라, globalVar라는 외부 변수를 변경하는 사이드 이펙트를 발생시킵니다.

사이드 이펙트의 문제점

사이드 이펙트는 코드의 예측 가능성을 떨어뜨리고, 디버깅을 어렵게 만들며, 테스트하기 어렵게 만듭니다. 함수가 외부 상태를 변경하면, 그 함수의 동작을 이해하고 예측하기 위해서는 함수 내부뿐만 아니라 외부 상태도 함께 고려해야 합니다.

예측 가능성 저하

사이드 이펙트를 가진 함수는 외부 상태에 의존하므로, 동일한 입력에도 불구하고 다른 결과를 반환할 수 있습니다.

디버깅의 어려움

사이드 이펙트를 가진 코드는 어디서 문제가 발생했는지 추적하기 어려워집니다. 외부 상태가 어디서 어떻게 변경되었는지 알아내야 하기 때문입니다.

테스트의 어려움

사이드 이펙트를 가진 코드는 순수 함수처럼 독립적으로 테스트하기 어렵습니다. 외부 상태를 조작하거나, 외부 시스템과의 상호작용을 모킹(mocking)해야 합니다.

리액트에서의 사이드 이펙트

리액트 애플리케이션에서는 컴포넌트가 렌더링되거나 업데이트될 때 다양한 사이드 이펙트를 처리해야 합니다. 예를 들어, API 호출, 구독 설정, 타이머 설정 등이 있습니다. 리액트는 이러한 사이드 이펙트를 관리하기 위해 useEffect 훅을 제공합니다.

useEffect 훅

useEffect 훅은 리액트 함수형 컴포넌트에서 사이드 이펙트를 수행하기 위해 사용됩니다. useEffect는 컴포넌트가 렌더링된 후에 실행되며, 특정 값이 변경될 때마다 다시 실행될 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import React, { useState, useEffect } from 'react';

function DataFetcher() {
    const [data, setData] = useState(null);

    useEffect(() => {
        fetch('https://api.example.com/data')
            .then(response => response.json())
            .then(data => setData(data))
            .catch(error => console.error('Error fetching data:', error));
    }, []); // 빈 배열을 두 번째 인수로 전달하여 컴포넌트가 마운트될 때 한 번만 실행

    return (
        <div>
            {data ? <p>{data}</p> : <p>Loading...</p>}
        </div>
    );
}

export default DataFetcher;

위 예제에서 useEffect 훅은 컴포넌트가 처음 렌더링될 때 한 번 실행되어 API에서 데이터를 가져오고, 그 데이터를 상태로 저장합니다.

클린업 함수

useEffect 훅은 선택적으로 클린업 함수를 반환할 수 있습니다. 클린업 함수는 컴포넌트가 언마운트되거나, 사이드 이펙트가 다시 실행되기 전에 실행됩니다.

1
2
3
4
5
6
7
8
9
useEffect(() => {
    const timer = setInterval(() => {
        console.log('Tick');
    }, 1000);

    return () => {
        clearInterval(timer); // 컴포넌트 언마운트 시 타이머 정리
    };
}, []); // 빈 배열을 두 번째 인수로 전달하여 컴포넌트가 마운트될 때 한 번만 실행

위 예제에서 클린업 함수는 타이머를 정리하여 메모리 누수를 방지합니다.

사이드 이펙트 관리 방법

1. 순수 함수 사용

가능한 경우, 외부 상태에 의존하지 않고, 입력값에 대해서만 동작하는 순수 함수를 사용합니다. 순수 함수는 동일한 입력값에 대해 항상 동일한 출력을 반환하며, 외부 상태를 변경하지 않습니다.

1
2
3
function add(a, b) {
    return a + b; // 순수 함수: 외부 상태를 변경하지 않음
}

2. 불변성 유지

상태를 변경할 때는 기존 상태를 직접 수정하지 않고, 새로운 상태 객체를 생성하여 반환합니다. 이는 예기치 않은 사이드 이펙트를 방지하고, 상태 관리의 예측 가능성을 높입니다.

1
2
3
const state = { count: 0 };

const newState = { ...state, count: state.count + 1 }; // 기존 상태를 변경하지 않고 새로운 상태 객체 생성

3. 상태 관리 라이브러리 사용

Redux와 같은 상태 관리 라이브러리를 사용하면, 상태를 중앙에서 관리하고, 상태 변경이 예측 가능하도록 할 수 있습니다. 이는 사이드 이펙트를 줄이고, 상태 관리를 더 체계적으로 할 수 있게 해줍니다.

결론

사이드 이펙트는 함수나 컴포넌트가 외부 상태나 시스템에 영향을 미치는 모든 작업을 의미합니다. 사이드 이펙트를 올바르게 관리하면 코드의 예측 가능성과 유지보수성을 높일 수 있습니다. 리액트에서는 useEffect 훅을 사용하여 컴포넌트의 사이드 이펙트를 처리하며, 순수 함수와 불변성을 유지하여 예기치 않은 사이드 이펙트를 방지할 수 있습니다.

오늘도 제 글을 읽어주셔서 감사합니다. 다음 시간에 더 유익한 주제로 찾아뵙겠습니다.

This post is licensed under CC BY 4.0 by the author.