👒 Vue 3. The composition API


VUE 3に新しく登場したTheComponentAPIについて知る.
import getPosts from './getPosts'
export default{
setup(){
// data
//methods
//computed
//lifecycle hooks
const data=getPosts()
}
}
1.Group logic together in a setup function
2.Easily create reusable logic(Functions)
サンプルコードを見てみましょう.
<template>
<div class="home">
home
<p ref='p'>My name is {{name}} and my age is {{age}}</p>
<button @click="handleClick">click me </button>
<input type='text' v-model='name'> //인풋에 작성하는대로 name이 변경된다
</div>
</template>
<script>
import {ref} from'vue'
export default{
  name:'Home',
  //setup() is always runs first before created and mounted..
  setup(){
  console.log('setup')
  const p = ref(null)
  console.log(p,p.value)
  
  //These are not reactive by default
  let name='mario'
  let age=30
  //we can use refs to create reactive values!
  const name=ref('mario')
  const age=ref(30)
  
  const  handleClick=()=>{
  console.log(p,p.value);
  p.value.classList.add('test')
  p.value.textContent='hello,ninjas';// 버튼 누르면 p 내용의 값이 바뀐다.
  //name과 age의 값이 변경된다(버튼 누르면)
name.value='loco'
age.value=29 
  }
  return {name,age,handleClick,p}
  }
  }
  </script>
👒 Refs vs Reactive
<template>
  <div class='home'>
   <h1>Home</h1>
   <h2>Refs</h2>
  <p> {{ninjaOne.name}}-{{ninjaOne.age}}</p>
  <button @click='updateNinjaOne'>Update ninja one</button>
<h2>Reactive</h2>
<p>{{ninjaTwo.name}}-{{ninjaTwo.age}}</p>
<button @click="updateNinjaTwo">Update ninja two</button>
</div>
</template>
<script>
import {ref,reactive} from 'vue'
export default {
  name:'Home',
  setup() {
    const ninJaOne=ref({name:'mario',age:30})
    const ninjaTwo=reactive({name:'luigi',age:34})
    
    const nameOne=ref('mario')
    const nameTwo=reactive('luigi');
    //luigi값은 primitive value이기에 업데이트 되지 못한다.
    const updateNinjaOne=()=>{
      🍏 ninjaOne.value.age=40
    }
    const updateNinjaTwo=()=>{
      🍏 ninjaTwo.age=45
         nameTwo='mario' // 전혀 업데이트 되지 않는다.
       
    return{ninjaOne,updateNinjaOne,ninjaTwo,updateNinjaTwo}
  }
}
refを使用する場合は、値に近づくために常に値を記入する必要があります.
ただし、reactiveを使用する場合はvalueを使用する必要はありません.
二つの中で何を使えばいいですか.reactiveは値の更新が難しい.いろいろな理由でrefを使うほうがいいです.
👒 Computed values
<template>
  <div class='home'>
    <h1>Home</h1>
    <input type='text' v-model='search'>
     <p>search term - {{search}}</p>
    <div v-for="name in matchingNames" :key="name">{{name}}</div>
  </div>
</template>
<script>
    import {computed,ref} from'vue'
export default {
  name:'Home',
  setup(){
    const search=ref('')
   const names=ref(['mario','yoru','luigi','tod','peach'])
   const matchingNames = computed(()=>{
     return names.value.filter((name) => name.includes(search.value))
                                      
   })
    return {names,search}
  }
}
</script>
👒 Using props in setup
<template>
  <div class="home">
    <h1>Home</h1>
  🍇 <PostList v-if='showPosts' :posts='posts' />
    //만약 showPosts가 false이면 이 컴포넌트는 언마운트되어서 안보이게 될 것이다.
    <button @click='showPosts =!showPosts'>toggle posts</button>
<button @click="posts.pop()"> delete a post </button>
 </div>
</template>
<script>
      🍇 import PostList from '../';
   import {ref} from 'vue'
  export default {
    name:'Home',
     🍇 components:{PostList},
    setup(){
      const posts = ref([
        {title:'welcome',body:'lorem',id:1},
        {title:'top 5 tips', body:'Lorem',id:2}
        ])
      const showPosts = ref(true)
      return {posts,showPosts}
    }
  }
</script>
==PostList.vue===
<template>
  <div class='post-list'>
    <div v-for='post in posts :key='post.id'>
     <h3>{{post.title}}</h3>
    </div>
 </div>
</template>
<script>
 export default {
  props:['posts'],
  setup(props) {
    console.log(props.posts)
                }
                }
</script>
👒 Lifecycle hooks in setup
<template>
  <div class='post-list'>
    <div v-for='post in posts :key='post.id'>
   <SinglePost :post='post'/>
    </div>
 </div>
</template>
<script>
 import { onMounted , onUnmounted,onUpdated} from 'vue'
 import SinglePost from './SinglePost.vue'

 export default {
  props:['posts'],
   components:{SinglePost},
  🍈 setup(props) {
     onMounted(()=>console.log('component mounted')
     onUnmounted (()=>console.log('component unmounted')
      onUpdated(()=>console.log('component updated'))
                }
                }
</script>
👒 Fetching data in setup
<template>
  <div class='home'>
    <h1> Home</h1>
  <div v-if='error'>{{error}} </div>
<div v-if="posts.length'>
   <PostList :posts='posts' />
     </div>
<div v-else > Loading...</div>
   </div>
</template>

<script>
import PostList from '../'
import {ref} from 'vue'

export default {
  name:'Home',
  components:{PostList},
  setup(){
    const posts=ref([])
    const error=ref(null)
    🕹 const load=async()=>{
      try{
        let data= await fetch('http://localhost:3000/posts'
                             )
        if(!data.ok){
          throw Error('no data available')
        }
        posts.value = await data.json()
      catch(err){
        error.value=err.message
        console.log(error.value)
      }
    }
      load();
    return {posts,error}
    
👒 Composition API & TypeScript
<template>
  <div class='app'>
    <p> {{ jobs[0]/location</p>
   </div>
 </template>
<script lang='ts'>
  import {defineComponent,reactive,toRefs,ref} from 'vue';
  im
  import Job from './types/Job';
  export default defineComponent ({
    name:'App',
    components:{},
    setup(){
      //const state = reactive ({
        //name:'Link',
        //age:25 as string | number <Type Assertion>
     // })
      //state.name =99999 //cannot change type
      //If I change the name as a number,this is not gonna work.
      //state.age='26'
      //return {...toRefs(state)}
      
      const name = ref('Link')
      const age = ref<number|string>(25); //we can use generic arguments instead of using type assertion
      age.value=26 가능
      age.value='26'가능해짐
      
      return {name,age}
      
      const jobs=ref<Job[]>([
        {title:'farm worker',location:'London' salary:30000,id:'1'}
           {title:'lawyer',location:'Newyork' salary:40000,id:'2'}
       {title:'engineer',location:'Paris' salary:30000,id:'3'}
        ])
        return {jobs}
      },
    
    methods:{
      changeName(name:string){
        this.name =name
        return name
      },
      changeAge(age:string|number){
        this.age = age
        return age
      }
    }
  });
</script>
====Job.ts==============
interface Job {
 title:string,
 location:string,
 salary:number,
 id:string
}
export default Job
注意:Youtube TheNet Ninja