쏙쏙 들어오는 함수형 코딩 - React.js

Haz·2023년 6월 5일
0
post-thumbnail

React와 함수형 프로그래밍


JavaScript 라이브러리, React.js

자바스크립트는 멀티 패러다임 언어

자바스크립트를 안다면, 어쩌면 이 글을 읽고 있는 당신은 욕부터 할 지도 모른다(?). 다른 언어들에 비해 자바스크립트는 객체 지향 언어라고 하기엔 부족하고, 함수형 언어라고 하기도 애매하다. 자바스크립트의 창시자인 Brendan Erich이 언어를 개발할 때 보기에 객체 지향은 부족하고, 함수형 프로그래밍이 궁금했다고 한다. 하지만 그와는 달리 다른 시니어 개발자들은 그동안 써왔던 객체 지향 언어를 선호했고, 결국 타협해낸 결과물이 함수형 패러다임을 기반으로 한 객체 지향 문법을 가진 자바스크립트다. 그래서 우리는 자바스크립트로 OOP 방식의 개발도 가능하고, 함수형 프로그래밍도 가능하다.

React.js로 함수형 프로그래밍?

위와 같은 이유로 자바스크립트 기반 프레임워크인 리액트는 당연히 함수형 프로그래밍이 가능하다. 심지어는 React의 Hook이나 상태 관리 라이브러리인 Redux에도 함수형 패러다임이 녹아있다.

그렇다면 React 코드에서 함수형 프로그래밍 관점인 액션, 계산, 데이터를 구별해보자

function App() {
  // 데이터
  const [count, setCount] = useState(0);
  
  // 계산
  const increase = (val) => val + 1;
  
  // 액션
  const onClick = () => setCount(increase(count));
  
  // 선언적 패턴
  return <button onClick={onClick}>{count}</button>
}

여기서도 중요한 건 카운트를 올리는 코드를 액션에 포함시킬 수도 있지만, 따로 구별해 increase() 함수로 만들었다는 점이다. 계산 함수, 즉 순수 함수는 많이 만들어도 부수 효과를 생성하지 않는다는 점에서 UI 개발에서도 함수형 사고를 한다면 도움이 된다.


React.js의 선언형 프로그래밍

선언형 프로그래밍이란?
필요한 것이 어떤 것인지 기술하는 데에 방점을 두고 애플리케이션의 구조를 세워나가는 프로그래밍 스타일

React.js는 바닐라 자바스크립트라면 명령형 프로그래밍으로 필요한 것을 하나하나 기술해야하는 부분을 추상화된 개념의 함수들을 활용해 아주 빠르게 프로그래밍할 수 있다.

  var target = document.getElementById('target');
  var wrapper = document.createElement('div');
  var headline = document.createElement('h1');

wrapper.id = "welcome";
headline.innerText = "Hello World";

wrapper.appendChild(headline);
target.appendChild(wrapper);

바닐라 자바스크립트로 DOM을 만든다고 하면 이렇게 Element와 그에 해당하는 속성을 일일이 나열하는 방식으로 프로그래밍해야한다.

하지만 React로 짠다면 어떨까?

  const Welcome = () => {
    return (
      <div id="target">
        <div id="welcome">
            <h1>Hello World</h1>
        <div>
      </div>
    )
  }

훨씬 HTML 코드 짜는 방식에 가깝고, 모르는 코드라도 추론하기 쉽다. 선언형 프로그래밍에서 코드 구문은 실제로 어떤 일이 발생해야하는지를 기술하고, 실질적으로 코드를 처리하는 작업은 추상화되어 숨겨져있다.

함수형 프로그래밍은 선언형 프로그래밍의 일종이다. 함수형 프로그래밍 또한 액션과 계산을 구분하여 변화하는 상태와 변동 가능한 데이터를 피하고, 코드가 어떻게 작동하는지보다는 무엇을 원하는지 파악하는 데에 집중되어있기 때문이다.


함수 컴포넌트와 함수형 프로그래밍

최근 React.js에서는 클래스형 컴포넌트가 아닌 함수 컴포넌트(function component)를 쓰도록 장려하는 것이 개발 트렌드로 자리 잡고 있다.

여기서 착각하기 쉬운 점은 함수 컴포넌트가 "함수형 컴포넌트(functional component)"가 아니라는 점이다. 아직 함수 컴포넌트가 개발 중인 상태일 때 실제로 React에서는 Functional Component, 즉 함수형 컴포넌트라고 이름 붙히려 했으나 함수형 프로그래밍 방법으로 개발한다는 혼란을 야기할 수 있어 이름을 변경했다고 한다. 함수형 컴포넌트라는 이름은 약 1년간 유지되다가 함수 컴포넌트로 변경됐다.

그렇다면 왜 함수형 컴포넌트라는 이름을 사용할 수 없었을까? 분명 함수형 프로그래밍이 적용되는 부분이 있는데 말이다.

위에서 들었던 예시처럼 useState 같은 hook의 존재는 함수형 프로그래밍을 가능하게 만들었다. hook이 도대체 뭐길래 이런 걸까?

class App extends Component {
  state = {
    count: 0,
  };
  
  countUpdate(n) {
  	this.setState({
    	count: n,
    });
  };
}

render() {
  const { count } = this.state;
  return (...);
}

예를 들어 함수형 프로그래밍이 useState hook 없다면 직접 객체를 만들어 데이터를 관리해야한다. 위 코드에서 보면 UI에서 버튼 클릭 시 state 내 count 값은 계속 올라가게 된다. 따라서 데이터를 신용할 수 없어진다.

이와 같은 문제로 인해 hook 없이는 함수형 프로그래밍이 원만히 이뤄지기 힘들다. 다만 hook이라고 해서 완전히 함수형 패러다임을 따르는 건 아니다. 예컨대, useEffect 같은 hook은 이름에서도 알 수 있듯이 특정한 Effect를 일으킨다. 부수 효과를 발생시킨다는 의미다. 함수형 프로그래밍의 엄격한 정의에 따르면 참조 투명성은 필수지만, 이와 다르게 함수 컴포넌트는 선택적으로 참조 투명성을 가지고 또 이를 관리한다.

그 외에도 만약 위와 같이 클래스형 컴포넌트라면 this는 변경이 가능하고, 조작도 가능하다는 문제점도 있다. 프론트엔드 개발에서는 최근 트렌드에 따라 비동기 통신에 의한 UI의 변경이 빈번하기 때문에 다른 UI 기능에 의해 this가 달라진다면 의도치 않게 엉뚱한 this를 호출하고 마는 것이다. 함수 컴포넌트라면 굳이 this를 쓸 필요 없이 함수 컴포넌트의 인자 값으로 받아서 props로 전달하면 값이 고정되기 때문에 함수형 프로그래밍이 가능하다.




"쏙쏙 들어오는 함수형 프로그래밍" 1장을 읽고 궁금해졌던 부분을 공부하며 리액트에 한발짝 다가간 느낌이다. 단순히 스킬적인 부분만 익히는 것보다도 리액트 자체에 대해서 알고, 공학적으로 무엇에, 어떻게 설계되었는지 그 기저를 들여다본 것 같아서 뿌듯하다😚

profile
나도 재밌고, 남들도 재밌는 서비스 만들어보고 싶다😎

0개의 댓글