Skip to content

프레임워크별 input 처리 방법

Published: at 오전 05:09

AstroJs는 Islands라는 개념을 사용해서 컴포넌트를 독립적으로 구성할 수 있다. 그 특징을 이용하면 하나의 페이지에서 react, vue, svelte 등 다양한 프레임워크를 혼용해서 사용할 수 있다. 이를 활용해 프레임워크별로 input을 처리하는 방법을 알아보자.

목차

펼치기

구성

총 5개의 input을 구성했다. 1. vue, 2. react, 3. lit, 4. svelte, 5. vanilla. 로직은 기본적으로 target에 input에 입력이 발생하면, 해당 입력 뒤에 ’!’를 붙여서 상태값을 변경하도록 구성했다.

코드: https://github.com/jinbekim/input

React

기본적으로 useState를 사용해서 상태값을 선언하고, onChange 이벤트를 통해 상태값을 변경한다. 랜더링은 setState가 실행될때마다 발생한다. 일반적인 html의 change이벤트와 다르게 리액트의 특성상 input이벤트인 onInput과 동일하게 작동하고, 보편적으로 onChange를 사용한다.

import { useState, type ChangeEvent, type EventHandler } from "react";

export const ReactInput = () => {
  const [inputValue, setInputValue] = useState('');
  const onInputChange: EventHandler<ChangeEvent<HTMLInputElement>> = (e) => {
    const value = e.target.value + '!';
    setInputValue(value);
  }
  return (
    <div style={{display: 'inline'}}>

    <input
      value={inputValue}
      onChange={onInputChange}
      />
      <span> value: {inputValue} </span>
      </div>
  );
}

Vue

ref를 사용해서 상태값을 선언하고, @input 이벤트를 통해 상태값을 변경한다. @inputinput 이벤트와 동일하게 작동한다.

<template>
  <div style="display: inline;">
    <input :value="value" name="VueInput" id="VueInput" @input="onInput"
    autocomplete="off"
    >
    <span> value: {{ value }}</span>
  </div>
</template>
<script setup lang="ts">
import { ref } from 'vue'

const value = ref('')
const onInput = (e: Event) => {
  value.value = (e.target as HTMLInputElement).value + '!'
}
</script>

Lit

웹컴포넌트를 사용하기 쉽게 만들어진 라이브러리이다. @state를 사용해서 상태값을 선언하고, @input 이벤트를 통해 상태값을 변경한다. 표준html을 사용하기 때문에 단순하고 빠르게 사용할 수 있다. 코드도 단순한진 모르겠지만, 개인적으로 웹표준에 가깝고, 실제로 가벼운 느낌이라 앞으로 더 사용해 보고 싶다. 단 render 메소드를 구현할때 ide의 도움을 제대로 받지 못하는 것 같아 아쉽다. 뭔가 방법이 있을 것도 같다.

import { html, LitElement, type PropertyValues } from "lit";
import { customElement, state } from "lit/decorators.js";

@customElement('lit-input')
export class LitInput extends LitElement {

  @state()
  private _value: string = "";

  handleInput(e: InputEvent) {
    this._value = (e.target as HTMLInputElement).value + '!';

    const value = this.shadowRoot?.getElementById('value');
    if (value) {
      value.textContent = ' value: ' + this._value;
    }
  }

  render() {
    return html`<div style="display: inline" >
    <input
      name="LitInput"
      id="LitInput"
      autocomplete="off"
      .value=${this._value}
      @input=${this.handleInput}
    />
    <span id="value"> value: </span>
    </div>
    `;
  }
}

Svelte

따로 상태를 선언하는 문법이 있지 않고, let으로 선언하고, on:input 이벤트를 통해 상태값을 변경한다. on:inputinput 이벤트와 동일하게 작동한다. 단순한 input이라 비교하긴 그렇지만, svelte코드 작성할때 제일 빨리 작성했다. 사용이 직관적인듯 하다.

<script lang="ts">
  import type { FormEventHandler } from "svelte/elements";

  let value = '';

  const handleInput: FormEventHandler<HTMLInputElement> = (e) => {
    value = e.currentTarget.value + '!';
  };
</script>
<div style="display: inline;">
  <input
  autocomplete="off"
  value="{value}"
  on:input={handleInput}
  />
  <span> value: {value}</span>
</div>

Vanilla

<script>
const _input = document.getElementById('VanillaInput') as HTMLInputElement;
let _value = '';

_input?.addEventListener('input', (e) => {
  _value = (e.target as HTMLInputElement).value + '!';
  _input.value = _value;

  const value = document.getElementById('value')!;
  value.textContent = 'Value: ' + _value;
});
</script>

<div style="display: inline;">
  <input
    id="VanillaInput"
    autocomplete="off"
    name="VanillaInput"
  />
  <span id="value" > value: </span>
</div>

실험

basic-input-test

테스트 결과 모든 프레임워크에서 input에 입력이 발생하면, 해당 입력 뒤에 ’!’를 붙여서 상태값을 변경하는 것을 확인할 수 있다. 하지만 지우는 경우에는 조금 다르다는걸 볼 수 있다. reactvanillainputvalue가 지워지지 않는 것을 확인 할 수 있다. 왜냐하면, react와 vanilla는 즉각적으로 inputvalue를 변경하기 때문이다. 반면에 vue, lit, svelte는 state의 변경이 감지되야 inputvalue가 변경되기 때문에 지워지는 것을 확인할 수 있다. 단반향 흐름, 양방향 흐름의 차이라고 생각했지만, 그저 랜더링 메커니즘의 차이로 보인다.

만약 vuesvelte에서 bind를 사용하면 어떻게 될까?

Vue input v-model

  <input v-model="value" >

Svelte input bind

  <input bind:value={value} />

basic-bind

이제 똑같이 지워지지 않는걸 확인할 수 있다.

결론

크게 결론내릴 것은 없지만, 프레임워크별로 input을 처리하는 방법을 알아 볼 수 있었고, 양방향 데이터 바인딩을 모델(데이터)의 변경과, 뷰(input)의 변경의 양방향적인 적용이라고 한다는 것을 알 수 있었다. 이번 실험은 로직에 따라서, 모델과 뷰의 상태가 끊길 수 있음을 알 수 있었다.