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하게 변경하는 방법
- 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>
-
- 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>
-
- ref 사용. 변수를 ref를 이용하여 선언하면 reactive 해진다. 해당 변수값 참조시 setup() 내에서는 .value를 붙이고 바깥에서는 해당 변수명을 그대로 참조하면된다.
- 내부에서 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 |