좋아요 버튼, 그 자체로 하나의 부품

532025년 10월 07일4

뉴스피드의 댓글 입력창을 리액트로 재구축하는 작업이 한창일 때, 톰은 팀에게 또 다른 작은 실험을 제안했다. 댓글 입력창처럼 복잡한 컴포넌트도 중요하지만, 리액트의 진정한 힘은 작고 재사용 가능한 부품을 만드는 데 있다는 것을 보여주고 싶었기 때문이다.

그의 시선이 향한 곳은 뉴스피드에서 가장 빈번하게 사용되는 UI, 바로 ‘좋아요’ 버튼이었다.

“생각해 보십시오. 현재 ‘좋아요’ 버튼은 그냥 클래스 이름 몇 개가 붙은 <a> 태그일 뿐입니다. 그 버튼을 누르면 어떤 일이 일어나는지에 대한 로직은 완전히 다른 자바스크립트 파일에 흩어져 있죠.”

그의 말이 맞았다. 게시물에 붙은 ‘좋아요’ 버튼과 사진에 붙은 ‘좋아요’ 버튼은 겉보기엔 같았지만, 내부적으로는 미세하게 다른 jQuery 셀렉터와 이벤트 핸들러에 의해 제어되고 있었다. 일관성이 없었고, 유지보수가 어려웠다.

“이 ‘좋아요’ 버튼을 완벽하게 독립된 하나의 리액트 컴포넌트로 만들어 봅시다. <LikeButton>이라는 이름으로요.”

팀은 이 작은 과제에 착수했다. 목표는 명확했다. <LikeButton>은 어디에 가져다 놓아도 스스로의 상태를 관리하며 완벽하게 동작해야 했다.

가장 먼저 props를 정의했다. 이 부품이 외부 세계로부터 알아야 할 정보는 무엇일까?
논의 끝에 두 가지가 결정되었다.

  • initialIsLiked: 이 버튼이 처음 렌더링될 때 ‘좋아요’가 눌린 상태인지 아닌지에 대한 여부 (true/false).
  • likeCount: 현재 총 ‘좋아요’ 개수.

다음으로 render 메서드를 작성했다. 여기서 핵심적인 질문이 다시 등장했다.
‘사용자가 버튼을 클릭하면, 버튼의 모양과 텍스트가 바뀌어야 한다. 이 변화하는 상태는 어디에 저장해야 하는가?’

예를 들어, initialIsLikedfalse였던 버튼을 사용자가 클릭하면, 이제 버튼은 ‘좋아요가 눌린’ 상태가 되어야 한다. 이 ‘눌렸다’는 정보는 props가 아니었다. 사용자의 행동에 의해 컴포넌트 내부에서 발생한 변화였다.

조던은 이 문제를 해결하기 위해, 리액트의 두 번째 데이터 소스인 state를 도입하기로 했다.

그는 <LikeButton>의 명세 객체 안에 새로운 코드를 추가했다.

var LikeButton = React.createClass({
  // 컴포넌트의 초기 내부 상태를 정의하는 메서드
  getInitialState: function() {
    return {
      isLiked: this.props.initialIsLiked, // props로 초기 상태를 설정
      currentCount: this.props.likeCount
    };
  },
  
  // ... 클릭 이벤트 핸들러 ...
  
  render: function() {
    // 이제 props가 아닌, this.state를 보고 렌더링한다.
    if (this.state.isLiked) {
      return React.createElement(
        'button', 
        { className: 'liked', onClick: this.handleClick }, 
        '좋아요 취소 (' + this.state.currentCount + ')'
      );
    } else {
      return React.createElement(
        'button', 
        { onClick: this.handleClick }, 
        '좋아요 (' + this.state.currentCount + ')'
      );
    }
  }
});

getInitialState라는 새로운 메서드가 등장했다. 이 메서드는 컴포넌트가 처음 만들어질 때 단 한 번 호출되며, this.state라는 내부 상태 객체의 초기값을 설정하는 역할을 했다. <LikeButton>은 부모에게 받은 props를 단지 초기 상태를 설정하는 데만 사용하고, 그 이후부터는 전적으로 자신의 state를 보고 렌더링했다.

이제 <LikeButton>은 단순한 UI 조각이 아니었다.
자신이 ‘좋아요가 눌린 상태인지 아닌지’를 스스로 기억하고, 그 기억에 따라 모습을 바꿀 수 있는, 마치 지능을 가진 듯한 부품이 된 것이다.

물론 아직 가장 중요한 조각이 빠져 있었다.
사용자가 버튼을 클릭했을 때, 이 this.state.isLiked 값을 false에서 true로 어떻게 ‘안전하게’ 바꿀 것인가? this.state.isLiked = true 라고 직접 수정하면 될까?

조던은 고개를 저었다. 그것은 리액트의 불변성 원칙과 단방향 데이터 흐름을 정면으로 위배하는, 금지된 행위였다. 상태를 바꾸기 위해서는 특별한 열쇠가 필요했다. 이 열쇠의 등장은 리액트의 마법이 실제로 일어나는 방식을 세상에 드러낼 터였다.