728x90

Option API

export default{
  data(){
    return{
    
    }
  },
  methods:{
  
  },
  computed:{
  
  },
  mounted(){
  
  }
}
  • 같은 종류의 일을 한다고 하더라고 코드가 data, mothods, computed, mounted에 떨어져 있을 수 있다. 즉, 응집성이 떨어진다

Composition API

export default{
  setup(){
    //data
    
    //methods
    
    //computed
    
    //lifecycle hooks
  }
}
  • 비즈니스 로직과 데이터를 setup() 이라는 함수에서 통합 관리할 수 있다. 응집성이 올라간다.

setup

  • 복잡한 로직에서 사용. react의 custom hook와 비슷하다.
<template>
<div  class="home">
  home
  <p ref="p"> My name is {{name}} and age is {{age}} </p>
  <button @click="handleClick">click me</button>
</div>

</template>

<script>
import {ref} from 'vue';

export default{
  setup(){
    console.log('set up');
  
    const p = ref(null);
  
    let name = 'mario';
    let age = 30;
  
    const handleClick = () =>{
      p.value.classList.add('test');
      p.value.textContext = 'hello';
    }
  
    return{
      name,
      age,
      p,
      handleClick,
    }
  }
}
</script>
  • created() 보다 먼저 실행된다
  • 반환 데이터 reactive하게 변경하는 방법
    1. ref 사용. 변수를 ref를 이용하여 선언하면 reactive 해진다. 해당 변수값 참조시 setup() 내에서는 .value를 붙이고 바깥에서는 해당 변수명을 그대로 참조하면된다.
      • <template>
        <div  class="home">
          home
          <p ref="p"> My name is {{name}} and age is {{age}} </p>
          <button @click="handleClick">click me</button>
        </div>
        
        </template>
        
        <script>
        import {ref} from 'vue';
        
        export default{
          setup(){
          
            let name = ref('mario'); // ref 내부 값은 초기값을 의미한다
            let age = ref(30);
          
            const handleClick = () =>{
              name.value = 'luigi';
              age.value = 35;
            }
          
            return{
              name,
              age,
              handleClick,
            }
          }
        }
        </script>
    2. reactive사용. 변수를 reactive를 이용하여 선언하면 reactive해진다. ref와 사용법은 유사하지만 setup()내에서 .value를 이용하지 않고도 변수값을 참조할 수 있다는점, primitive type이 초기값으로 주어져서는 안된다는 점이 유일하게 다르다
      • <template>
        <div  class="home">
          home
          <p ref="p"> My name is {{ninja.name}} and age is {{ninja.age}} </p>
          <button @click="handleClick">click me</button>
        </div>
        
        </template>
        
        <script>
        import {reactive} from 'vue';
        
        export default{
          setup(){
          
            const ninja = reactive({name:'mario',age:30});
          
            const updateNinja = () =>{
              ninjaOne.age=40;
            }
          
            return{
              ninja,
              updateNinja,
            }
          }
        }
        </script>
  • 내부에서 computed를 사용할 수 있다.
    • <template>
      <div  class="home">
        <input type="text" v-model=search/>
        <ul v-for="name in names" :key="name">
          <li>{{name}}</li>
        </ul>
      </div>
      
      </template>
      
      <script>
      import {computed,ref} from 'vue';
      
      export default{
        setup(){
          
          const search = ref('');
          const names = ['mario','yoshi','luigi','toad','bowser','koopa','peach'];
          
          const filteredNames = computed(()=>{
            return names.filter((name)=>name.includes(search.value));
          })
          
          return{
            search,
            names:filteredNames
          }
        }
      }
      </script>
  • watch, watchEffect를 사용할 수 있다.
    • watch: Vue2에서 일반적으로 사용하던 watch와 동일. observe할 value를 등록후 해당 값이 변경되면 callback함수 실행
    • watchEffect: callback 함수 내부 변수의 dependency를 찾아 해당 dependency 변수값이 변경되면 callback함수가 자동으로 실행된다. watchEffect 의 반환값을 대입 받은 변수를 실행하면 watchEffect는 destroy된다.
    • // 다음은 search 값이 변경되면 자동으로 watch, watchEffect의 callback 함수를 실행하게 만든 코드이다.
      // handleClick 실행시 watch와 watchEffect는 메모리를 반환한다.
      <script>
      import {watch,watchEffect,ref} from 'vue';
      
      export default{
        setup(){
          
          const search = ref('');
          const names = ['mario','yoshi','luigi','toad','bowser','koopa','peach'];
          
          const stopWatch = watch(search,()=>{
            console.log('watch function ran');
          })
          
          const stopEffect = watchEffect(()=>{
            console.log('watchEffect function ran',search.value);
          })
          
          const handleClick = ()=>{
            stopWatch();
            stopEffect();
          }
          
          return{
            search,
          }
        }
      }
      </script>
  • props를 받을 수 있다.
    • // PostList.vue
      // posts props가 넘어온 상황
      <script>
      export default{
        props: ["posts"], //props를 선언해줘야한다.
        setup(props){
          console.log(props.posts)
        }
      }
      </script>
  • vue lifecycle을 이용할 수 있다. setup 밖의 동일한 lifecycle보다 먼저 실행된다.
    • <script>
      export default{
        setup(props){
          onMounted(()=>console.log("component Mounted"));
          onUnMounted(()=>console.log("component UnMounted"));
          onUpdated(()=>console.log("component Updated"));
        }
      }
      </script>

componentAPI에서 data fetch

setup()에 async를 선언않고 setup() 내부에 async function을 생성해 이를 호출한다.

<template>
  <div class="Home">
    <div v-if="error">{{error}}</div>
    <div v-if="posts.length">
      <PostList :posts="posts"/>
    </div>
    <div v-else>
      Loading...
    </div>
  </div>
</template>

<script>
import {ref} from 'vue'
export default{
  setup(){
    const posts= ref([]);
    const error = ref(null);
    
    const load = async() =>{
      try{
        let data = await fetch('asdf');
        if(!data.ok){
          throw new Error('no data available'
        }
        posts.value = await data.json(); 
      }catch(e){
        error.value = e.message;
        console.log(error.value);
      }
    }
  }
}
</script>

Reusable Composables

여러 컴포넌트에서 같은 로직의 setup()을 사용할 경우 코드를 반복해서 사용하는것은 비효율적이다.

다른 파일로 떼어놓고 필요할때마다 호출하여 사용할 수 있다.

//composables/getPosts.js
import {ref} from 'vue';

const getPosts = () =>{
  const posts = ref([]);
  const error = ref(null);
  
  const load = async()=>{
    try{
      let data = fetch('asdf')
      if(!data.ok){
        throw new Error('no data available');
      }
      posts.value = await data.json();
    }catch(e){
      error.value = e.message;
      console.error(error.value);
    }
  }
  //load(); //넣지않는다
  
  return {posts,error,load}
}

export default getPosts;
//Home.vue
<script>
export default{
  import getPosts from '../composables/getPosts'
  setup(){
    const {posts,error,load} = getPosts(); // 처음에 posts와 error은 비어있는 상태. 뒤에 load가 호출되면 값이 채워진다.
    load() // getPosts에 집어넣지 않는다.
    return {posts,error}
  }
}
</script>

Vue3 + Typescript 설정 방법

npm install -g @vue/cli

 

vue --version 4.5.8

 

vue create vue-3-and-typescript

 

Babel

Typescript

3.x

 

no class style component

 

eslint+prettier

 

lint on save

 

구조

main.ts : equivalent to main.js

shims-vue.d.ts : Helper file for Typescript. No need to modify it. give better definition showing what's going on vue files

tsconfig.json : configure options for ts compiler

 

add ts to existing vue 3 project

vue add typescript -> vue/cli upgrade

use class-style component syntax ? no

use babel alongside typescript? yes

convert all .js files to .ts ? yes

skip type checking of all declaration files ? yes

 

 

# creating components with Typescript

<script lang="ts">

import {defineComponent } from 'vue' : import Vue helper function

define component that works well with typescript

single file component에 설정할 것 전부이다.

 

# Type Fundamentals

Common Javascript types often encountered : String, Number, Boolean, Array, Function, Object

Typescript provides additional types to Javascript 

- Any : essentially disables any type checking

- Tuple : fixed length arrays with predefined data types

- Enum : allows you to define friendly names to a set of values

enum ArrowKeys {

  Up, // 1

  Down, //2

  Left= 0 , // 0

  Right = 5 //4

}

등등 더있음

 

Object 타입 정의방법

let person : {

  name : string

  age : number;

  activeAvenger: boolean;

  powers : string[];

} = {

  name: 'Peter Parker',

  age: 20,

  activeAvenger : true,

  powers: ['wall-crawl', 'spider-sense']

}

 

Limitaions of Predefined Types

 

The need for custom types is a common one. -> Type and Interface

 

What is Type

Type allows you to define alias how the data should be shaped.

 

type buttonType = 'primary' | 'secondary' | 'success' | 'danger'

let buttonStyles: buttonType = 'primary' // O

let buttonStyles : buttonType = 'error' // X

 

What is Interface

type for object

 

interface Hero {

  name : string;

  age : number;

  activeAvenger : boolean;

  powers : string[];

  universe : ComicUniverse; // type ComicUniverse = 'Marvel' | 'DC'

}

 

let person:Hero = {

  name: 'Peter Parker',

  age: 20,

  activeAvenger : true,

  powers: ['wall-crawl', 'spider-sense'],

  universe : 'Marvel'

}

 

Use Type except for an Object

 

# Data With Custom Types

Install VSCode extension VueDX : provide edtior service

 

src 폴더 밑에 types.ts 생성

export interface EventItem {

 id : number

 category : string

 title : string

 description : string

 location: string

 date: string

 time: string

 organizer: string

}

 

//Eventdetail.vue

import {EventItem} from '../types'

 

data(){

  event : {} as EventItem // Type Assertion

}

 

# Props With Types

 

import {EventItem, PropType} from '../types' // PropType: helper method

 

props : {

  event: {

   type: Object as PropType<EventItem>, // type : EventItem , type : Object as EventItem쓰면 에러뜬다. Props에서는 Vue에서 지정한 방법으로 타입을 지정해야한다

   required: true

  }

}

 

What is Generic?

function createList (item: number) : number[]{ // createNumberList가 아니야 reusable하게 다른 타입에서도 작동하게 만들자 => Generic

 const newList : number[] = [];

 newList.push(item);

 return newList;

}

 

const numberList = createList(123);

 

Generic은 함수에서 사용되는 변수의  type을 Dynamic하게 정의할 수 있도록 해준다

function createList<CustomType>(item: CustomType) : CustomType[]{

  const newList: CustomType[] = [];

  newList.push(item);

  return newList;

}

const numberList = createList<number>(123)

const stringList = createList<string>("Hello");

 

# Custom Methods with CustomTypes

 

1. Computed

For computed properties, focus on what type is returned

 

data(){

  return {

   events: [] as EventItem[]

  }

},

computed:{

  firstEvent(): EventItem {

   return this.events[0]

  }

}

 

2. Methods

For methods, add types for the parameters and return value if applicable

 

data(){

  return {

   events: [] as EventItem[]

  }

},

methods:{

  addEvent(newEvent: EventItem) {

   this.events.push(newEvent)

  },

  secondEvent(): EventItem{

   return this.events[1]

  }

}

 

# Composition API with Typescript

data: () => ({

  newTask : {

   label: '',

   type: 'personal',

  } as TodoItem,

  taskItems: [] as TodoItem[],

  listFilter: 'all'

}),

computed: {

  filteredTasks() : TodoItem[] {

   if(this.listFilter == 'complete'){

    return this.taskItems.filter((item:TodoItem) => item.isComplete === true)

   }else if(this.listFilter === 'incomplete'){

    return this.taskItems.filter((item.TodoItem)=>item.isComplete === false)

   }else{

     return this.taskItems

   }

  }

},

methos:{

  addTask() {

   this.taskItems.push({

     ...this.newTask,

     isComplete:false

   })

  }

}

 

Refactor this in composition api

 

setup(){

  const state = reactive({

  newTask : {

   label: '',

   type: 'personal',

  } as TodoItem,

  taskItems: [] as TodoItem[],

  listFilter: 'all'

});

 

  const filteredTasks = computed(()=> { // computed 내부의 return 타입을 보고 타입추론을 해준다

   if(state.listFilter == 'complete'){

    return state.taskItems.filter((item:TodoItem) => item.isComplete === true)

   }else if(state.listFilter === 'incomplete'){

    return state.taskItems.filter((item.TodoItem)=>item.isComplete === false)

   }else{

     return state.taskItems

   }

  })

 

  const addTask = ()=> {

   this.taskItems.push({

     ...this.newTask,

     isComplete:false

   })

  }

  return {

    ...toRefs(state),

    addTask, 

    filteredTasks

  }

 

}

'VueJS' 카테고리의 다른 글

Vue3 - 3.Type Fundamentals  (0) 2021.12.28
Vue3 - 2. Vue3 + Typescript  (0) 2021.12.28
vue3 - 0.주요 특징  (0) 2021.12.10
array / object prototype  (0) 2021.06.27
VueJs Project Architecture  (0) 2021.01.28

+ Recent posts