꼬멘트 + 리액트

최근에 꼬멘트에 리액트를 적용했다.


짜잔 🥳

비포 github.com/kkeundotnet/kkoment/blob/014bac/client/kkoment.ts
애프터 github.com/kkeundotnet/kkoment/blob/f8a6c6/client/src/main.tsx
(줄 수에는 차이가 거의 없다.)

애초에 꼬멘트가 큰 프로그램이 아니라 크게 바뀐 부분은 없다. 단지 예전엔 수동으로 DOM을 고쳐 주었는데 지금은 리액트가 알아서 해주는 부분들이 있다.

예를 들어, 예전에는 새 댓글을 달 때 (1) 서버에 전체 댓글 목록을 다시 요청하고, (2) 새롭게 추가된 댓글들만 수동으로 골라, (3) 수동으로 DOM에 추가했었다. 대략 이런 식이다.

for (let comment of comments) {
    if (comment.id <= last_id) { // (2)
        continue;
    }
    comments_elem.appendChild(make_comment_elem(comment)); // (3)
    last_id = comment.id;
}

하지만 이제는 자잘한 일, (2)와 (3)은 직접 하지 않아도 된다. 리액트 "상태"에 저장된 전체 댓글 목록을 새로운 댓글 목록으로 바꾸면, 실제로 바뀐 부분만 찾아서 DOM을 업데이트하는 건 리액트가 대신 한다. 랜더링에 필요한 "상태"를 정의하게 하고 이용하기 때문에 손으로 대충 하는 것보다는 더 잘 할 여지가 많다.

this.setState({ comments: comments });

그래도 타입스크립트는 자바스크립트다. 😢

타입스크립트가 많은 문제를 해결해 주기는 하지만, 그럼에도 여전히 변수 바인딩은 헷갈리고 위험하다. 예를 들어, 어떤 클래스 안에서 정의된 함수가 this를 사용할 때, 그 this는 함수가 정의될 때가 아니라 호출될 때 바인딩된다. 매번 봐도 적응이 안 된다. 그러니까 그 함수를 콜백과 같은 이유로 다른 곳에 보내면 그 아이는 그 길로 나와는 남남인 것이다.

이런 문제를 피하기 위해 리액트 문서에서는 애가 다른 곳에 보내지기 전에 this를 강제로 바인딩하기를 추천한다.
reactjs.org/docs/handling-events.html

constructor() {
    this.handleClick = this.handleClick.bind(this);
}

이 명령은 this.handleClick을 꺼내 와 this를 바인딩하고 그 결과를 다시 this.handleClick에 저장한다.


그럼 리스크립트(ReScript) 쓰면 되지? 🤐

나도 처음엔 그렇게 생각했다. 리스크립트 문서를 다 읽고 신나는 마음으로 코딩을 시작했는데 역시 세상은 인기 없는 언어에게 그리 호락호락하지 않다.

빔과 VSCode는 지원하면서 이멕스 지원이 없다. 흐음... 어떻게 참을 수는 있다. 눈물은 조금 나지만.
rescript-lang.org/docs/manual/latest/editor-plugins

유일하게 필요한 라이브러리가 텍스트창 크기를 자동으로 수정해 주는 autosize인데 리스크립트용은 못 찾겠다. 직접 만들거나 자바스크립트용 라이브러리를 바인딩하면 된다. 흐음... 데자뷰가 느껴진다.
blog.kkeun.net/computer/2020-04-13-ocaml-webserver-failed

하지만 리스크립트 대신 타입스크립트를 쓰는 방법도 있다. 심지어 이미 꼬멘트는 타입스크립트로 되어 있다. 타입스크립트의 이멕스 지원도 빠방하다. 마음에 걸리는 함수 바인딩 부분만 눈감아 주면 아무 문제 없다. 나만 모른척 하면 아무도 모른다.

그렇게 결국 꼬멘트는 세상 사용자 많은 타입스크립트에 머물게 되었다. 왠지 씁슬한 패배감이 맴돌지만 빠른 포기가 보통 건강에 좋다. 🤭

2022-03-02 씀.