본문 바로가기
코딩 정보/React

불변성이 중요해요! 그게 머죠? 너무 막연한데요..

by 꽁이꽁설꽁돌 2024. 9. 14.
728x90
반응형

목차

     

     

    오늘은 리액트에서 빠질 수 없는 불변성이라는 개념을 정리하고자 한다.

     

    불변성의 정의

    불변성의 의미는 상태를 변경하지 않는 것이라는 간단한 정의로 설명된다. 이렇게 말하면 정말 와닫지 않는다.

    그렇다면 불변성이 이야기하고 있는 상태의 변경이라는 것이 정확히 어떤 행위를 의미하는 것일까? 단순히 프로그램의 변수를 변경하거나 재할당 하지 않는 것을 이야기하는 것일까?

     

    사실 불변성이 이야기하는 상태의 변경이라는 것은 단순한 변수의 재할당을 이야기하는 것이 아니다. 정확히 말하면 메모리에 저장된 값을 변경하는 모든 행위를 의미하며, 여기에 변수의 재할당과 같은 행위도 포함되는 것이다.

     

     

    그렇다면 우리가 변수를 재할당하지만 않는다면 불변이라는 개념을 지킬 수 있는 것일까?

    답을 알기 위해서는 다음의 개념을 이해해야 한다.

     

    값에 의한 호출과 참조에 의한 호출

    참조에 의한 호출

    function updateValue(x) {
      x = x + 1;
      console.log("Inside function:", x); // 11
    }
    
    let num = 10;
    updateValue(num);
    console.log("Outside function:", num); // 10

     

    값에 의한 호출

    function updateArray(arr) {
      arr[0] = 99;
      console.log("Inside function:", arr); // [99, 2, 3]
    }
    
    let numbers = [1, 2, 3];
    updateArray(numbers);
    console.log("Outside function:", numbers); // [99, 2, 3]

     

    전자는 원본을 바꾸지 않는 반에 후자는 원본을 바꾸어 버린다. 왜 이런 결과가 발생하는 것일까?

     

    값에 의한 호출 방식은 함수의 인자로 어떤 변수를 넘길 때 해당 변수가 가지고 있는 값을 그대로 복사하여 함수에게 넘겨주는 방식을 의미하기 때문에, 기존에 str 변수가 가리키고 있는 메모리 공간에 있는 값을 함수에 인자로 넘기는 것이 아니라 그 값을 복사하여 새로운 메모리 공간에 저장하고나서 넘겨준다는 뜻이다.

     

     

    그에 반해서 참조에 의한 호출 방식 “변수가 가리키고 있는 메모리 공간의 주소”를 넘기는 방식이다.

    즉, arr 변수가 가리키고 있는 메모리 공간에 저장된 배열과 updateArray 함수가 인자로 받은 배열은 정확히 같은 메모리 공간에 저장되어 있는, “같은 배열” 이라는 것이다.

     

     

    그렇다면 여기서 의문이 든다 불변성은 왜 지켜야 하는거지??

     

    불변성의 장점

    1. 무분별한 상태의 변경 막기

    let greeting = 'Hi';
    
    function setName () {
      name = 'Evan';
    }
    
    setTimeout(() => {
      greeting = 'Hello';
    }, 0);
    
    setName();
    console.log(`${greeting}, ${name}`);

     

    다음과 같은 코드가 있다고 하면 정말 추적이 어려워 진다.

    왜냐하면 전역으로 할당되어 암묵적으로 setTimeout에서 변수가 재할당되기 때문이다.

    가장 큰 문제점은 오류가 아니기 때문에 더 추적이 어렵다 

     

    2. 상태 변경의 추적 용이성

    const numbers = [1, 2, 3];
    
    function addNumber(numbers, num) {
      return [...numbers, num]; // 불변성 유지: 새로운 배열을 생성
    }
    
    const updatedNumbers = addNumber(numbers, 4);
    
    console.log("Original:", numbers);      // [1, 2, 3]
    console.log("Updated:", updatedNumbers); // [1, 2, 3, 4]

     

    자바스크립트의 객체의 프로퍼티나 배열의 원소를 변경해야하는 경우, 필연적으로 불변성이 깨질 수 밖에 없다.

    이렇게 새로운 객체를 생성하게 되면 의도하지 않은 객체의 상태 변화도 방어할 수 있고 상태 변화를 추적할 수도 있게 된다. 왜냐하면 addNumber 함수가 뱉어낸 객체는 numbers 객체와는 전혀 다른, 새로운 객체이기 때문이다.

     

     

    FP(함수형 프로그래밍) vs OOP(객체지향 프로그래밍)

    객체지향 프로그래밍은 private과 같은 접근 제한자로 상태를 외부에 노출시키지 않음으로써 사용자가 단순한 인터페이스를 접할 수 있도록 하지만, 함수형 프로그래밍은 아예 프로그램의 상태를 변경하지 않는 불변성을 지향하면서 프로그램의 동작을 예측하기 쉽고 단순하게 만든다.

     

    간단하게 설명하면 OOP는 변경 가능한 상태를 감추어 단순함을 만들어내고

    FP는 아예 변경 가능한 상태를 없앰으로써 단순함을 만들어 낸다.

     

    리액트를 통해 예시를 들면 다음과 같다.

     

    OOP의 특징

    import React, { useState, useEffect } from 'react';
    
    // 카운터 로직을 캡슐화한 커스텀 훅
    function useCounter(initialCount = 0) {
      const [count, setCount] = useState(initialCount);
    
      const increment = () => setCount(count + 1);
      const decrement = () => setCount(count - 1);
    
      useEffect(() => {
        console.log('Counter component mounted');
        return () => {
          console.log('Counter component will unmount');
        };
      }, []);
    
      return { count, increment, decrement };
    }
    
    // 함수형 컴포넌트에서 커스텀 훅을 사용
    function Counter() {
      const { count, increment, decrement } = useCounter();
    
      return (
        <div>
          <p>Count: {count}</p>
          <button onClick={increment}>Increment</button>
          <button onClick={decrement}>Decrement</button>
        </div>
      );
    }
    
    export default Counter;

     

    FP의 특징

    import React, { useState } from 'react';
    
    function MyComponent() {
    //함수형 컴포넌트는 순수 함수로서, 입력(props)에 따라 항상 동일한 출력을 생성한다.
      const [count, setCount] = useState(0);
    
      const increment = () => {
        setCount(count + 1);
      };
    
      return (
        <div>
          <p>Count: {count}</p>
          <button onClick={increment}>Increment</button>
        </div>
      );
    }
    
    export default MyComponent;

     

    참고

    https://evan-moon.github.io/2020/01/05/what-is-immutable/

     

    변하지 않는 상태를 유지하는 방법, 불변성(Immutable)

    이번 포스팅에서는 순수 함수에 이어 함수형 프로그래밍에서 중요하게 여기는 개념인 에 대한 이야기를 해보려고 한다. 사실 순수 함수를 설명하다보면 불변성에 대한 이야기가 꼭 한번은 나오

    evan-moon.github.io

     

     

    반응형