ETC -

vue3 composition API

  • -

안녕하세요 TriplexLab입니다.

vue3에서 추가된 setup function을 이용한 composition API에 대해서 살펴 보겠습니다. [링크참고]
바로 아래 예시를 보면 될것 같습니다.

vue3에서 추가되었다고 하지만 vue2(^2.6.14)에서도 사용가능 합니다.

먼저 composition API본격적으로 알아보기 전에 setup에 대해서 살펴보도록 하겠습니다.
setup함수 인자로는 props로 상위 컴포넌트에서 데이터를 받을수 있습니다.
그리고setup함수안에서 가공된 데이터를 리턴하면, 다른 함수(메소드)에서 접근이 가능합니다.

<!-- MyBook.vue -->
<template>
  <div>{{ collectionName }}: {{ readersNumber }} {{ book.title }}</div>
  <button @click="incresement">incresement</button>
</template>

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

export default {
  props: {
    collectionName: String,
  },
  setup(props) {
    const readersNumber = ref(0);
    const book = reactive({ title: "Vue 3 Guide" });
    const incresement = () => {
      readersNumber.value += 1;
    };
    // expose to template
    return {
      readersNumber,
      book,
      incresement,
    };
  },
  created(){
    this.init()
  },
  method: { //setup함수안에서 가공된 데이터를 리턴하면, 다른 함수(메소드)에서 접근이 가능합니다.
    init(){
      console.log(this.book.title = 'tetet')
      this.incresement()
      console.log(this.readersNumber)
    }
  }
};
</script>

중요한 차이점은 setup 함수는 컴포넌트 인스턴스가 생성되기 전에 실행된다는 점이다. 즉 컴포넌트 인스턴스에 접근이 필요한 기능은 사용할 수 없다. 즉 setup 안에서 this를 통해 컴포넌트 객체의 data, computed, methods 에서 선언한 것들에는 접근이 불가능하다. 그리고 인스턴스가 생성된 직후에 호출되는 created 메소드에 매칭되는 라이프 사이클 훅도 존재하지 않는다.

ref는 단일 데이터만 담을때 사용할 용도입니다.(ref 안에서는 계산속성을 사용할 수 없음)
예를 들어서 한가지 string값이라든지, boolean값이라든지 등등만 넣어서 반응성을 가진 데이터로 만들고 싶을때 사용하는것입니다.

const count = ref(0)
const boolean = ref(false)
const string = ref('triplexlab')

다음과 같이 사용해서 변수에 할당된것을 확인 해보면

<template>
  <button @click="count++">{{ count }}</button>
</template>

<script>
import { ref } from 'vue'

export default {
  setup() {
    const count = ref(0) //단일데이터를 넣을 ref

    // 템플릿 및 기타 옵션 API 후크에 노출
    return {count}
  },

  mounted() {
    console.log(this.count) // 0 👈🏻결과
  }
}
</script>

reactive는 object 데이터를 담을때 사용할 용도입니다.(reactive 에서는 계산속성 사용가능)

바로 아래 예시1)를 보시죠.

예시1)

<template>
  {{ username }}
  {{ age }}
</template>

<script>
  import { reactive, toRefs } from 'vue'
  export default {
    setup(){
      const state = reactive({
        username: 'TriplxLab',
        age: 20
      });
      // return { 다음과 같이 리턴하면 반응성 손실, 값 변경시 재렌더링 동작 안함!!
      //   username: state.username, 
      //   age: state.age  
      // } 
      return toRefs(state)
    }
  }
</script>

👉🏻 toRefs의 특징은 다음과 같다.

  • toRefs 는 구성 요소가 반응성을 잃지 않고, 반환된 객체를 분해 / 확산할 수 있도록 컴포지션 함수에서 반응 객체를 반환할 때 유용하다.
  • toRefs 는 reactive 객체에 포함된 속성에 대한 참조만 생성한다. 특정 속성에 대한 참조를 만드려면 toRef를 사용해야 함

예시2)
reactive로 되어 있는값을 변경하는 함수를 만들어 보겠습니다.

<template>
  <div>
    {{ username }}
    {{ age }}
    <button @click="changeFun">변경</button>
	<br/>
    <input type="text" v-model="username">
  </div>
</template>

<script>
import { toRefs, reactive } from 'vue';
export default {
  name: 'App-22299e',
  setup(){
    const state = reactive({
      username: 'TriplxLab',
      age: 50
    })
    
    function changeFun() {
      state.username = 'ddsf'
      state.age = 30
    }

    return {...toRefs(state), changeFun}
	}
}
</script>

composables(컴포저블)를 활용한 로직 분리 및 재사용

다음은 vue의 composables(컴포저블)를 활용해서 위에서 다룬 ref, reactive를 예시를 보여 드리겠습니다.
Vue 애플리케이션의 맥락에서 "컴포저블"은 Vue의 Composition API를 활용하여 상태 저장 로직 을 캡슐화하고 재사용하는 기능입니다.[링크참고]

예시1) useObjectState

// composables/useObjectState.js

import { reactive, toRefs } from 'vue';

const useObjectState = (initialValue = {}) => {
  const text = 'useObjectState 인자로 넣는것은 Object로만 넣어야 합니다.'
  if(initialValue.constructor !== Object) {
    console.warn(text)
  }
  let stateObject = reactive(initialValue);
  const setStateObject = (newState) => {
    stateObject = newState(stateObject)
  }
  return [toRefs(stateObject), setStateObject];
};

export default useObjectState;
// src/App.vue

<template>
  <div>
    {{ username }}
    {{ age }}
    <br/>
    <input type="text" v-model="username">
    <br/>
    <button @click="changeFu">변경 버튼</button>
  </div>
</template>

<script>
import useObjectState from '@/composables/useObjectState.js';
export default {
  name: 'App-22299e',
  setup(){
    const [stateObject, setStateObject] = useObjectState({
      username: 'TriplxLab',
      age: 30
    });
    return {...stateObject, setStateObject}
  },
  methods: {
    changeFu() {
      this.setStateObject(() => {
        this.username = 'TriplxLab2!!!'
        this.age = '20'
      })
    }
  }
}
</script>

예시2) useReducer

// composables/useReducer.js

import { ref } from 'vue';

const useReducer = (initialArg, reducer) => {
  let state = ref(initialArg);
  const dispatch = (action) => {
    state.value = reducer(state.value, action);
  };
  return [state, dispatch];
}

export default useReducer;
// src/App.vue

<template>
  <div>
    {{ state.count }}
    <button @click="dispatch({ type: 'decrement', mode: {step: 1} })">
      -
    </button>
    <button @click="dispatch({ type: 'increment', mode: {step: 1} })">
      +
    </button>
    <input type="text" v-model="state.count" >
  </div>
</template>

<script>
import useReducer from '@/composables/useReducer.js';
export default {
  name: 'App-22299e',
  setup(){
    const initialState = { count: 0 }
    function reducer(state, action) {
      switch (action.type) {
        case 'increment':
          return { count: state.count + action.mode.step }
        case 'decrement':
          return { count: state.count - action.mode.step }
        default:
          throw new Error('잘못된 타입 입니다!')
      }
    }
    const [state, dispatch] = useReducer(initialState, reducer);
    return {state, dispatch}
  }
}
</script>
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.