Vue.js Composition API(feat."data(){}")

강정우·2023년 4월 7일
0

vue.js

목록 보기
39/72
post-thumbnail
post-custom-banner

특징

  • 우선 Vue3로 넘어오면서 가장 크게 바뀐 점이 될것이다.
    • 조금 다른방식으로 컴포넌트를 구축하는데 이게 완전히 바뀌는게 아니고 템플릿과 스타일링은 그대로이고 프로퍼티나 사용자 설정 이벤트도 그대로인데 컴포지션 API를 사용하면 JavaScript 코드는 달라진다.
  • 이것은 온전히 선택사항이다. 참고로 지금까지 포스팅해온 방법은 Options API라고 한다.

Options API 의 단점

  1. 같이 있어야 하는 로직이 여러 가지 옵션 즉, data(), methods, 연산 등에 나뉘어 있는 상황이다.
    • 예를들어 한 컴포넌트에 장바구니, 로그인 로직이 같이 있다면 이것을 각각 data(){}, methods:{} 에 맞춰 무조껀 나눠야했다는 것이다.
  2. 컴포넌트의 로직을 재사용하는 것이 까다롭거나 복잡해질 수 있다. 로직을 재사용하는 다른 방법도 있지만 모두 단점이 있어서 최적이라곤 할 수 없다.
    • 앞서 boiler plate를 보면 알겠지만 굉장히 직관적이지 못하고 복잡하다.

Setup(){}

  • 앞서 말한 Options API의 1단점을 극복하고자 setup() 메서드를 사용해서 로직을 번들로 만들어 컴포넌트 구성 객체에 추가하는 것이다.

  • 위치는 data(){}, methods:{} 와 동일한 위치에 선언해주면된다.

  • setup(){}data(){}, methods:{}, computed:{},watch:{} 을 대체(통합)한다.

    • setup() 메서드를 템플릿에 활용하면 앞서 말한 각종 데이터와 상호작용이 가능해진다.
    • 또한 components:{}, props:[]는 바뀌지 않는다.
  • 템플릿 코드나 v-if, 데이터 바인딩 같은 기능은 배운 내용 그대로이다.

    • 컴포넌트 구성 객체의 코드 설정만 바꾸는 것이다.

ref

<template>
  {{userName}}
</template>

...
    setup(){
        const urName = ref('정우');
        return {userName:urName};
    }
...
  • 여기서 나온 ref는 앞전에 input에 사용하던 ref와는 다르다.

  • setup()에서 호출할 수 있는 함수라는 점에서 다르다. ref는 소위 참조를 생성하는데 DOM 요소에 대해서 참조하는 것이 아니라 값을 참조해서 템플릿에서 쓸 수 있게 해준다. 이렇게 하면 반응형 문자열이 생성된다.

ref는 아무런 값이나 생성하는 것이 아니라 반응형 값을 생성하기 때문에 이 값을 바꾸면 Vue도 인식하고 감시할 수 있어서 값이 바뀌거나 템플릿에 사용되면 Vue는 DOM에서 템플릿을 업데이트할 수 있다.

  • 여기서는 this. 키워드는 사용하지 않는다. setup() 메서드에서 this. 키워드를 사용할 수는 있지만 methods에서 사용했을 때처럼 Vue 구성 객체를 참조하지 않는다.

    • 왜냐하면 setup()은 Vue가 컴포넌트 초기화 프로세스의 초반에 실행하는 메서드라서 컴포넌트가 제대로 초기화되지 않은 시점에 실행되기 때문에 this. 키워드로 대상에 액세스할 수 없는 것이다.
    • 그래서 props:[] 에도 접근할 수 없을 것이다.
  • 작동방식 : 내부적으로는 객체를 생성하고 문자열은 그 객체에 저장이 되고 Vue는 이 객체를 감시해서 기존 문자열이 아닌 새로운 값을 배치하면 변화를 인식하고 DOM을 업데이트한다.

언제나 "객체"를 "반환"한다.

ref 값 동적 할당

앞서 ref를 사용하는 이유는 reactive한 값을 가질 수 있기 때문이라고했는데 값을 한번 바꿔보자

...
    setup(){
        const urName = ref('정우');

        setTimeout(function (){
            urName = "개발자"
        },2000);
        return {userName:urName};
    }
...
  • 이렇게 하면 오류가 난다. 왜? 우선 변수를 const로 선언함 2번 const가 아닌 let으로 한다고 해도 이 경우에는 문자열이 기존 ref를 덮어쓰므로 기존 ref를 잃게 되는데 Vue에 값이 변화하면 알려주는 ref의 내장 메커니즘이 필요하기 때문에 ref가 없어지면 안 되기 때문이다.

  • 그렇다면 어떻게 바꿔주면 좋을까?

...
    setup(){
        const urName = ref('헬창');

        setTimeout(function (){
            urName.value = "개발자"
        },2000);
        return {userName:urName};
    }
...
  • setup 메서드는 한 번만 실행되는데 이때 템플릿에 새 값과 객체를 반환하지 못한 것이다.
    그렇기 때문에 ref가 필요한 거고 따라서 uName에 이런 식으로 새로운 값을 지정할 일이 없으므로 상수를 사용하는 것이다.

  • ref 함수가 객체를 생성한다고 언급하였는데 내부적으로 객체에는 .value 프로퍼티가 포함된다. ref 함수에 전달하는 값은 value 프로퍼티에 저장되고 uName 객체에서 .value 프로퍼티에 새로운 값을 지정할 수도 있다.

마크업 컴포넌트

<template>
  <section class="container">
    <h2>{{ userName }}</h2>
  </section>
</template>
  • setup() 메서드의 반환 객체에서 ref를 활용한 경우 Vue가 자동으로 .value 프로퍼티의 값을 가져가므로 <h2>에서는 .value에 액세스하지 않는다.

  • userName은 ref를 가리키고 있고 새로운 값을 설정하려면 .value 프로퍼티를 사용해야 한다. 그러나 ref를 템플릿에 전달하면 Vue는 자동으로 .value 프로퍼티를 확인한다. 따라서 템플릿에서는 .value를 쓸 필요가 없이 ref만 사용하면 Vue가 나머지를 처리하는 구조이다.


prop drilling

...
    setup(){
        const user = ref({
          name: '헬창',
          age: 27
        });

        setTimeout(function (){
            user.value.name = "개발자"
        },2000);
        return {userName:user.vlaue.name, userAge:user.value.age};
    }

	console.log(user);
...
  • 이렇게 넣으면 과연 reactive하게 작동할까? => NO!

    • ref 객체를 보면 게터(getter)와 setter도 있고 Vue는 이 둘로 value 프로퍼티가 액세스되고 그 값이 확인되거나 변경되는 것을 파악한다.
    • 일례로 user.value에 액세스하고 새로운 객체를 지정하면 Vue는 이 변화를 감지할 수 있다.
  • 만일 ref의 값으로 객체를 전달하면 Vue가 객체 내부의 변화도 파악할 수 있도록 그 객체는 Proxy로 래핑된다.\

    • 예를 들어서 user.value.name을 보면 객체 내부에 새로운 이름을 배정했다.
    • 그런데 Vue가 이런 변화를 파악할 수 있다고 설명한 것과 달리 Vue는 애플리케이션에서 정보를 업데이트할 수 없다.
  • 문제는 템플릿에 정보를 전달하는 방식에 있다. return 문에서도 객체 내부의 정보를 액세스한다. user.value를 사용해서 ref에 저장된 객체에 액세스하여 이름과 나이 프로퍼티에 접근할 수 있는데 바로 여기에서 문제가 발생한 것이다.

    • 이름과 나이 프로퍼티에 있는 이름 및 나잇값은 평범한 문자열과 숫자이지 반응형 값이 아닌 것이다!
    • 이론상으로는 사용자 객체에 변화가 생기면 Vue가 파악해야 하지만 사용자 객체 내부 정보를 이렇게 직접 파악하고 있기 때문에 템플릿에서 사용자 정보를 활용한다는 것을 인지하지 못하는 것이다.
  • Vue는 문자열과 숫자가 활용된다는 것만 알 수 있는데 이렇게 구체적인 값의 정보는 지속해서 파악하지 못하기 때문에 변화를 감지하지 못 하는 것이다.

마크업 컴포넌트

<template>
  <section class="container">
    <h2>{{ user.name }}</h2>
    <h2>{{ user.age }}</h2>
  </section>
</template>
<script>
    setup(){
        const user = ref({
          name: '헬창',
          age: 27
        });

        setTimeout(function (){
            user.value.name = "개발자"
        },2000);
        return {user: user};
    }
</script>
  • 따라서 setup() 에는 미가공 객체를 전달하는 것이 중요하다.
    미가공 ref 객체를 받으면 객체 내부의 반응성을 인지하고 새로운 값이 지정되거나 템플릿에서 사용될 때를 알기 때문에 먼저 템플릿에서 객체 사용 위치를 찾아서 코드를 업데이트해준다.

reactive

<script setup>
import {reactive, ref} from 'vue';

const user = reactive({name:'alex',age:27})
const refUser = ref({name:'alice', age: 22})

setTimeout(function (){
    user.name = '응가'
    refUser.value.age = 26
},2000);
</script>
  • reactive는 ref와 비슷하지만 객체용으로 만들어졌다는 점에서 다르다.
    사용자 상수에서 ref 대신에 reactive를 호출하고 기존 객체를 reactive에 전달한다.

  • ref는 문자열, 숫자, 객체 등 다양한 값을 사용했다면 reactive는 객체만을 이용한다.

  • reactive는 중요한 작업을 하나 하는데 이름과 나이를 value 프로퍼티를 갖는 객체로 래핑하고 기존 값에 포인터를 가리키는 게 아니라 reactive에 전달한 객체를 프록시로 래핑해서 반응형으로 만들어서 객체를 사용할 수 있게 해준다. 마치 래퍼가 없는 것처럼 사용할 수 있는 것이다.

전에는 ref 객체로 value 프로퍼티와 게터와 세터를 값으로 가졌다면 이제는 프록시 객체가 객체를 래핑하고 내부 리스너로 프로퍼티의 변화를 감시한다.

profile
智(지)! 德(덕)! 體(체)!
post-custom-banner

0개의 댓글