unref

  • argument 가 ref 인 경우 내부 value return
function useFoo(x: number | Ref<number>) {
  const unwrapped = unref(x) // unwrapped is guaranteed to be number now
}

toRef

  • 반응성 객체에 ref 사용할 때 씀
  • prop로 ref 넘길 때 용이
const state = reactive({
  foo: 1,
  bar: 2
})

const fooRef = toRef(state, 'foo')

fooRef.value++
console.log(state.foo) // 2

state.foo++
console.log(fooRef.value) // 3
export default {
  setup(props) {
    useSomeFeature(toRef(props, 'foo'))
  }
}

toRefs

  • 일반 객체에서 반응성 객체로 바꿈
  • 여기서 결과 객체의 각 속성은 원본 객체의 해당 속성을 가리키는 참조
  • 반응성 객체를 반환 시 용이
const state = reactive({
  foo: 1,
  bar: 2
})

const stateAsRefs = toRefs(state)
/*
Type of stateAsRefs:

{
  foo: Ref<number>,
  bar: Ref<number>
}
*/

// The ref and the original property is "linked"
state.foo++
console.log(stateAsRefs.foo) // 2

stateAsRefs.foo.value++
console.log(state.foo) // 3
function useFeatureX() {
  const state = reactive({
    foo: 1,
    bar: 2
  })

  // logic operating on state

  // convert to refs when returning
  return toRefs(state)
}

export default {
  setup() {
    // can destructure without losing reactivity
    const { foo, bar } = useFeatureX()

    return {
      foo,
      bar
    }
  }
}

isRef

  • ref 객체 값 체크

isProxy

  • reactive 이거나 readonly 일 때 객체 체크

isReacitve

  • reactive에 의해 만들어진 반응형 proxy 객체 체크
  • 만약 프록시가 readonly로 만들어 진경우 true return
  • 다른 프록시가 reactive에 의해 만들어진 다른 프록시가 감쌈

isReadonly

  • readonly로 만들어진 객체가 readonly인지 체크

'Vue.js > vue3' 카테고리의 다른 글

[vue3] composition API  (0) 2020.09.30
[vue3] Reactivity APIs  (0) 2020.07.02
[vue3] setup  (0) 2020.07.02
[vue3] vue 2 > vue3  (0) 2020.07.02
<template>
  <div>
    <p>Spaces Left: {{ spacesLeft }} out of {{ capacity }}</p>
    <h2>Attending</h2>
    <ul>
      <li v-for="(name, index) in attending" :key="index">
        {{ name }}
      </li>
    </ul>
    <button @click="increaseCapacity()">Increase Capacity</button>
  </div>
</template>
<script>
import { ref, computed } from "vue";
export default {
  setup() {
        // 변화 감지할 데이터 ref 로 묶음
    const capacity = ref(4);
    const attending = ref(["Tim", "Bob", "Joe"]);
    const spacesLeft = computed(() => {
            // ref 로 묶은 데이터 접근시 .value 사용해서 접근 해야함
      return capacity.value - attending.value.length;
    });
        // 함수는 function으로 정의
    function increaseCapacity() {
      capacity.value++;
    }
        // 템플릿에서 해당값들을 접근 가능
    return { capacity, attending, spacesLeft, increaseCapacity };
  }
};
</script>
import { reactive, computed, toRefs } from "vue";
export default {
  setup() {
        // 반응성 값들을 object 로 반환
        // ref와 다르게 .value로 접근할 필요 없음
    const event = reactive({
      capacity: 4,
      attending: ["Tim", "Bob", "Joe"],
      spacesLeft: computed(() => { return event.capacity - event.attending.length; })
    });
    function increaseCapacity() {
      event.capacity++;
    }
        // toRefs로 반응성을 가지고 있는 일반 객체를 만듦 
    return { ...toRefs(event), increaseCapacity };
  }
<template>...</template>
<script>
export default {
    setup() {
        const product = useSearch()
        const result = useSorting()
        return {product, result}
    }
}

function useSearch(getResult) {

}
function useSorting({ input, options }) { 
}
</script>

'Vue.js > vue3' 카테고리의 다른 글

[vue3] Reactivity Utilities  (0) 2020.09.30
[vue3] Reactivity APIs  (0) 2020.07.02
[vue3] setup  (0) 2020.07.02
[vue3] vue 2 > vue3  (0) 2020.07.02

reactivity apis

reactive

  • 모든 속성에 영향을 준다
  • object가 아닌 proxy를 반환
const obj = reactive({ count: 0 })

ref

  • ref object 반환하고 반응성을 반환하고 값을 반환함
  • ref object 는 .value로 값을 가져옴
  • 객체가 참조 값으로 할당되면 반응 방법에 의해 객체 반응
const count = ref(0)
console.log(count.value) // 0

count.value++
console.log(count.value) // 1
  • 템플릿에서 사용할때는 .value를 사용할 필요 없음

  • 반응성 객체 접근

    ref는 반응성 객체를 접근 변경하기 위해서는 자동으로 랩이 해제되어 일반 속성 처럼 동작

const count = ref(0)
const state = reactive({
  count
})

console.log(state.count) // 0

// state.count.value =1 -> X
state.count = 1
console.log(count.value) // 1
  • 현재 ref에 연결된 값이 새로운 ref로 변경됨
  • ref는 reative object에 있을때만 랩이 해제된다
const otherCount = ref(2)

state.count = otherCount
console.log(state.count) // 2
console.log(count.value) // 1
  • array나 collection 타입과 같은 것을 접근할 때 랩을 해체하는 행동이 아니다
const arr = reactive([ref(0)])
// need .value here
console.log(arr[0].value)

const map = reactive(new Map([['foo', ref(0)]]))
// need .value here
console.log(map.get('foo').value)

computed

  • getter 함수를 가져오고 불변의 반응성 ref object를 반환
const count = ref(1)
const plusOne = computed(() => count.value + 1)

console.log(plusOne.value) // 2

plusOne.value++ // error
  • 대안으로, get,set 함수로 object 가져올 수 있음
const count = ref(1)
const plusOne = computed({
  get: () => count.value + 1,
  set: val => {
    count.value = val - 1
  }
})

plusOne.value = 1
console.log(count.value) // 0

readonly

  • 일반, 반응성 객체를 가져오고 읽기만 가능한 proxy를 반환
const original = reactive({ count: 0 })

const copy = readonly(original)

watchEffect(() => {
      // 반응성 관련 일
  console.log(copy.count)
})

// 원본 변경시 사본 감지
original.count++

// 실패 하고 그리고 경고를 반환
copy.count++ // warning!

watchEffect

  • 반응성을 트래킹하며 즉시 함수 시작
  • 의존적인게 바뀌게 되면 바로 re-run
const count = ref(0)

watchEffect(() => console.log(count.value))
// -> logs 0

setTimeout(() => {
  count.value++
  // -> logs 1
}, 100)
  • watcher 멈추는 법
    • setup() 함수를 부르는 동안 watcheffect가 호출됨
    • 컴포넌트 생명주기에 watcher 이 연결 되어 있고 자동적으로 컴포넌트가 unmounted될때 멈춤
const stop = watchEffect(() => {
  /* ... */
})

// later
stop()
  • 무효화의 단점
    • 가끔 watched 함수는 비동기의 단점임
watchEffect(onInvalidate => {
  const token = performAsyncOperation(id.value)
  onInvalidate(() => {
    // id has changed or watcher is stopped.
    // invalidate previously pending async operation
    token.cancel()
  })
})
  • DOM에서 watch를 사용하고 싶으면 mounted 훅에서 사용
onMounted(() => {
  watchEffect(() => {
    // access the DOM or template refs
  })
})
  • watcher 동기 이거나 컴포넌트가 업데이트 된 후 효과가 있음
// fire synchronously
watchEffect(
  () => {
    /* ... */
  },
  {
    flush: 'sync'
  }
)

// fire before component updates
watchEffect(
  () => {
    /* ... */
  },
  {
    flush: 'pre'
  }
)
  • watcher debugging
    • onTrack, onTrigger 옵션이 디버그 watcher 행동을 해줌
    • onTrack - 반응성 property가 호출되거나 ref가 의존되어있을 때
    • onTrigger - watcher반환하거나 변화가 의존되어있을 때
    • 두개의 callback는 debugger event 반환함
watchEffect(
  () => {
    /* side effect */
  },
  {
    onTrigger(e) {
      debugger
    }
  }
)

watch

  • 구체적인 데이터 자원을 요구하고 각각의 콜백 함수에 단점이 적용된다
  • watched할 데이터가 변화가 있을때만 call 된다
  • 한개의 데이터
// watching a getter
const state = reactive({ count: 0 })
watch(
  () => state.count,
  (count, prevCount) => {
    /* ... */
  }
)

// directly watching a ref
const count = ref(0)
watch(count, (count, prevCount) => {
  /* ... */
})
  • 여러개 데이터 - array 이용
watch([fooRef, barRef], ([foo, bar], [prevFoo, prevBar]) => {
  /* ... */
})

'Vue.js > vue3' 카테고리의 다른 글

[vue3] Reactivity Utilities  (0) 2020.09.30
[vue3] composition API  (0) 2020.09.30
[vue3] setup  (0) 2020.07.02
[vue3] vue 2 > vue3  (0) 2020.07.02

setup

  • 새로운 옵션
  • 컴포넌트 안에서 composition api 사용하는 진입점

호출 시점

  • 컴포넌트 instance가 생성될때 props 초기화 이후
  • beforeCreate 훅 이전에 호출
  • object 반환
  • object 속성은 컴포넌트 템플릿에서 사용된다
<template>
  <div>{{ count }} {{ object.foo }}</div>
</template>

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

  export default {
    setup() {
      const count = ref(0)
      const object = reactive({ foo: 'bar' })

      // expose to template
      return {
        count,
        object
      }
    }
  }
</script>

setup을 통해서 반환되는 refs는 자동적으로 템플릿 접근 시 감싸있지 않다. 그래서 .value를 사용할 필요가 없다

  • setup은 render 함수를 반환 할 수 있음

    같은 범주에 선언되어 있는 reative state를 바로 접근 할 수 있게 해줌

import { h, ref, reactive } from 'vue'

export default {
  setup() {
    const count = ref(0)
    const object = reactive({ foo: 'bar' })

    return () => h('div', [count.value, object.foo])
  }
  • aruguments

    • props의 첫번째 인자를 함수에서 받음

        export default {
          props: {
            name: String
          },
          setup(props) {
            console.log(props.name)
          }
        }
    • props 객체는 반응성임

      watchEffect, watch로 새로운 props가 전달될 때 확인할 수 있음

        export default {
          props: {
            name: String
          },
          setup(props) {
            watchEffect(() => {
              console.log(`name is: ` + props.name)
            })
          }
        }

      props객체를 해체를 하면 반응성을 잃음

        export default {
          props: {
            name: String
          },
          setup({ name }) {
            watchEffect(() => {
              console.log(`name is: ` + name) // Will not be reactive!
            })
          }
        }

      props객체는 개발하는 동안 불변

      만약, 사용자 코드를 변경하려고 시도하면 경고함

      setup의 두번째 인자는 context 객체(vue2와 this처럼 ) 제공

        const MyComponent = {
          setup(props, context) {
            context.attrs
            context.slots
            context.emit
          }
        }

      attrs와 slots는 내부 구성요소의 proxy

      이를 통해 항상 최근 값을 노출하고 오래된 참조에 접근 하지 않고도 값을 구조화 할 수 있음

        const MyComponent = {
          setup(props, { attrs }) {
            // 최근 상테를 가져옴
            function onClick() {
              console.log(attrs.foo) // 가장 최근 참조 보장
            }
          }
        }
  • this

    setup()에서는 사용 불가

'Vue.js > vue3' 카테고리의 다른 글

[vue3] Reactivity Utilities  (0) 2020.09.30
[vue3] composition API  (0) 2020.09.30
[vue3] Reactivity APIs  (0) 2020.07.02
[vue3] vue 2 > vue3  (0) 2020.07.02

사용해야하는 이유

  • 큰 컴포넌트의 가독성을 높임
  • 뷰 2는 코드 재사용시 약점 있음
  • typescript 지원 제한

가독성 문제점

vue2 문제점

  • 검색창을 만드는 경우 vue2는 같은 정보를 여러 곳에 추가해야 함
  • components, props, data, computed, methods, lifecycle methods ⇒ 6개의 옵션이 있음
  • 아주 복잡함 !!! 한번에 두면 더 읽기 쉬울 것 같음
export default{
    data() {
        // search data
        // sorting 
    }
    methods:{
        // search data
        // sorting
    }
}

vue 3 해결책

  • composition api 를 통해 새로운 구문을 만듦
  • 단, 문제점이 있음
    • setup 에 다 넣는 경우 setup이 길어 질수 있음
export default {
    setup() {
        // search data
        // sorting
    }
}
  • 해결책
export default {
    setup() {
        return { ...useSearch(), ...useSorting() }
    }
}
function useSearch() {
    // search data
}
function useSorting() {
    // sorting
}

컴포넌트 재사용의 문제점

vue 2 문제점- mixins

단점

  • 변수명 충돌 가능
  • 관계가 명확하지 않음
  • 재사용 하기 어려움
const productSearchMixin = {
    data () {
        return {
                // search data
        }
    },
    methods: {
        // search func
    }
}

const resultSortMixin = {
    data() {
        return {
            // sorting data
        }
    },
    methods: {
        // sorting func
    }
}
export default {
    mixins: [productSearchMixin, resultSortMixin]
}

vue3 해결책

  • 각각의 함수는 수정 가능한 mixins을 반환

장점

  • 재사용 용이
  • 관계가 분명해짐

단점

  • 명확한 이름을 지정해 줘야함
  • 복잡한 porperty 추가시 mixin 어떤 porperty가 보여지는지 알아야함
// mixins/factories/search.js
export default function searchMixinFactory({...}) {
    // search function
}
//  mixins/factories/sorting.js
export default function sortingMixinFactory({...}) {
    // sorting function
}
// search.vue
// 이 파일에서 위의 두개의 파일로 각각의 설정들을 보냄
import searchMixinFactory from '@mixins/factories/search'
import sortingMixinFactory from '@mixins/factories/sorting'

export default {
    mixins: [
        searchMixinFactory({
            namespace: 'productSearch'
        }),
        sortingMixinFactory({
            namespace: 'resultSorting'
        })
    ]
}

Mixins problem 해결책 - scoped slots

단점

  • 들여쓰기 증가
  • 노출된 properties 만 템플릿에서 사용가능하다
  • 한 개 대신 세 개의 컴포넌트를 사용해야함 > 약간 귀찮음
// componets/generic-sorting.vue
<script>
export default {
    props: ['input','options'],

}
</script>
<template>
    <div>
        <slot v-bind ="{options, index,output}"/>
    </div>
</template>
// componets/generic-search.vue
<script>
export default {
    props: ['getSearch']
}
</script>
<template>
    <div>
        <slot v-bind="{query, results, rum}"/>
    </div>
</template>
// search.vue
<template>
    <GenericSearch :get-results="getProducts" v-slot="productSearch">
        <GenericSorting 
            :input = "productSearch.result"
            :options=resultSortingOptions"
            v-slot="resultSorting"
        >

vue3 의 composition api

장점

  • 약간의 코드로 컴포넌트에 쉽게 넣을 수 있음
  • 친숙한 코드
  • mixins과 scoped slot 의 유연성 (함수에서만)

단점

  • 배움이 필요함
// use/search.js
export default function useSearch(getResults) {
    // search func
}
// use/sorting.js
export default function useSorting({input, options}) {
    // sorting func
}
// search.vue
import useSearch form '@use/search'
import useSorting from '@use/sorting'
export default {
    setup() {
        const productSearch = useSearch(~)
        const resultSorting = useSorting({~~})

        return {productSearch, resultSorting}
    }
}

언제 composition api 사용하는가

  • 컴포넌트가 너무 커지고 구조화를 원할때
  • 컴포넌트 재사용 높임
  • typescript support

'Vue.js > vue3' 카테고리의 다른 글

[vue3] Reactivity Utilities  (0) 2020.09.30
[vue3] composition API  (0) 2020.09.30
[vue3] Reactivity APIs  (0) 2020.07.02
[vue3] setup  (0) 2020.07.02

+ Recent posts