2024-01-08 반응성 (WIP)

2024-01-08
  • JavaScript

항상 텍스트가 너무 많아

솔직히 글을 잘 쓰고 싶은 마음이 별로 없다. 누군가를 이해시키기 위한 글은 충분히 많이 쓰고 있다. 기술 블로그의 컨셉을 어떻게 가져가야 할지 고민을 하기도 했지만 가독성 같은거 신경 쓰다간 내 공부를 못한다.

하루에 한개 씩 늘리는 푸시업을 오늘 자로 81개 했고, 하루도 거르지 않았다. 처음엔 자세도 매우 엉성했지만 지금은 나름 정자세에 가까워진 것 같다. 한 세트에 하는 갯수도 5개에서 25개로 늘었다. 그렇다. 일단 하는게 중요하다. 세부 사항은 저절로 따라온다.

그런 의미에서…

‘반응성(Reactivity)‘에 대해 정리하지 말고 주절거려보자

현대 프론트엔드와 반응성은 뗄레야 뗄 수 없는 관계다. 움직이지 않는 웹 페이지는 어색하다. 사실 웹 페이지가 사용자의 동작에 반응하여 특정 기능을 수행하는 건 꽤나 많은 개념을 경유하고 번거로운 과정을 거쳐야 한다.

우리 회사 BDC(빅데이터 센터) 연구원 분들끼리 자체적으로 사용할 데이터 시각화 웹 제품을 직접 만들 요량으로 React 스터디를 하신다기에 오늘 공부 커리큘럼을 봐드렸다. <모던 리액트 Deep Dive>을 기반으로 도장 깨기를 계획하고 계셨다. 개인적으로 잘 보고 있는 기술 블로그를 운영하시는 분이 쓰신 책이고 목차도 좋아서 읽어보진 않았다면 감히 추천할만한 책(구매 링크)이라고 생각한다.

하지만 모든 일에는 순서가 있는 법이다. 먼저 정보 전달 문서로서의 HTML과 스타일 시트로서의 CSS를 익혀야 한다. 의외로 많은 백엔드 개발자 혹은 프론트엔드 지망생들이 CSS의 부조리함(ex. 세로 중앙 정렬) 앞에 무릎을 꿇고 이 지점에서 상당수 떨어져 나간다.

그 다음으로는 위에서 언급한 HTML 요소를 자바스크립트로 지정하여 DOM에 EventListener를 등록하여 사용자의 입력을 받는 방법에 대해 공부해야 한다. 이 과정에서 자바스크립트의 기본적인 문법과 기본적인 활용을 익힐 수 있다. 여기까지 이르러서야 웹 페이지는 사용자의 입력에 반응하는 웹 애플리케이션으로 거듭날 수 있다. jQuery를 사용하면 이 과정을 좀 더 쉽게 처리할 수 있다.

하지만 사용자의 입력에 반응한다고 해서 곧장 ‘반응성’을 갖는 것은 아니다. jQuery와 현대 웹 프레임워크와의 차이는 자동화 정도의 차이에 있다. jQuery는 개발자가 DOM 요소를 직접 조작하여 수동으로 DOM을 조작하여 화면을 업데이트 해야 한다.

반면, 현대의 프론트엔드 프레임워크(예: React, Vue, Angular)는 ‘선언적’ UI 업데이트를 지원한다. 이들 프레임워크에서는 UI의 상태를 데이터 모델과 연결하고, 데이터가 변경될 때 UI가 자동으로 업데이트된다. 개발자는 데이터 모델의 상태만 관리하면 되고, UI의 실제 업데이트는 프레임워크가 처리해준다. 비즈니스 로직 작성에 좀 더 집중할 수 있으므로 생산성이 크게 향상된다.

세상엔 다양한 반응성이 (양방향 vs 단방향)

그래서 반응성이란… 내 생각에 반응성은 어떠한 변수 A의 변경에 따라 이를 사용하는 UI의 각 부분이 자동적으로 자신의 DOM 상태를 변경하는 것이다. 따라서 변수와 UI 각 부분 사이에는 어떠한 연결고리가 있어야 한다. 이 연결고리를 바인딩(Binding)이라고 한다.

바인딩은 양방향으로 이루어질 수도 있고 단방향으로 이루어질 수도 있다. 양방향 바인딩은 데이터와 UI가 서로 영향을 주고 받는 경우이다. 예를 들어, 사용자가 입력 필드에 텍스트를 입력하면 해당 데이터가 변경되고, 이 데이터가 다른 곳의 UI 요소에도 반영된다. 또한, 데이터의 변경이 입력 필드의 표시 내용을 변경할 수도 있다.

반면 단방향 바인딩은 데이터의 변경은 UI에 반영되지만, UI의 변경이 데이터에 영향을 주지 않는 경우이다. 이 경우, 데이터는 ‘단일 출처(single source)의 진리’로 작용하며, UI는 오직 데이터에 의해서만 변경된다.

양방향 바인딩의 대표적인 예시로는 Vue, Svelte, 단방향 바인딩에의 예시로는 React, Solid 등이 대표적이다. 아래 예시 코드를 보면 양방향 바인딩에서는 setter 함수를 사용하지 않고도 데이터의 변경이 UI에 반영되는 것을 볼 수 있다. 반면 단방향 바인딩에서는 별도의 setter 함수를 사용해야 한다.

:: Vue

<template>
  <div>
    <input v-model="text" type="text" />
    <p>{{ text }}</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      text: "",
    };
  },
};
</script>

:: Svelte

<script>
  let text = '';
</script>

<input bind:value={text} type="text" />
<p>{text}</p>

:: React

import React, { useState } from "react";

function App() {
  const [text, setText] = useState("");

  const handleChange = (event) => {
    setText(event.target.value);
  };

  return (
    <div>
      <input type="text" value={text} onChange={handleChange} />
      <p>{text}</p>
    </div>
  );
}

export default App;

:: Solid

import { createSignal } from "solid-js";

function App() {
  const [text, setText] = createSignal("");

  const handleChange = (event) => {
    setText(event.target.value);
  };

  return (
    <div>
      <input type="text" value={text()} onInput={handleChange} />
      <p>{text()}</p>
    </div>
  );
}

export default App;

내부 코드로 살펴보기

나는 이제 정말이지 코드를 떠올리지 않고서는 아무 것도 배울 수 없는 지경에 이르렀다. 내가 가장 모르겠는 vue의 반응성 메커니즘 부터 내부 코드로 살펴보자.

Profile picture

saengmotmi

'내가 원하는 건 문학이 아닌 기쁨이다.'