Publish to my blog (weekly)
-
- Because the component instance is not yet created when
setup
is executed, there is nothis
inside asetup
option. - methods
- lifecycle hooks
- computed properties
- That’s because in JavaScript, primitive types like
Number
orString
are passed by value, not by reference: - Now whenever we call
getUserRepositories
,repositories
will be mutated and the view will be updated to reflect the change.
-
-
- we recommend using kebab-cased event listeners when you are using in-DOM templates. If you're using string templates, this limitation does not apply.
- emits: ['inFocus', 'submit']
- When a native event (e.g.,
click
) is defined in theemits
option, the component event will be used instead of a native event listener. - Similar to prop type validation, an emitted event can be validated if it is defined with the Object syntax instead of the array syntax.
- // No validation click: null,
- // Validate submit event submit: ({ email, password }) => { if (email && password) { return true } else { console.warn('Invalid submit event payload!') return false } }
- .$emit('submit', { email, password })
- child component will expect a
title
prop and emitsupdate:title
event to sync: - props: { title: String }, emits: ['update:title'],
- :value="title"
- @input="$emit('update:title', $event.target.value)"
- v-model:first-name="firstName"
- v-model:last-name="lastName"
- firstName: String,
- lastName: String
- 'update:firstName'
- 'update:lastName'
- :value="firstName"
- @input="$emit('update:firstName', $event.target.value)"
- :value="lastName"
- @input="$emit('update:lastName', $event.target.value)"
-
- v-model.capitalize="myText"
- modelModifiers: { default: () => ({}) }
- console.log(this.modelModifiers) // { capitalize: true }
- modelModifiers: { default: () => ({}) }
- emitValue(e) { let value = e.target.value if (this.modelModifiers.capitalize) { value = value.charAt(0).toUpperCase() + value.slice(1) } this.$emit('update:modelValue', value) }
- :value="modelValue"
- @input="emitValue"
- For
v-model
bindings with arguments, the generated prop name will bearg + "Modifiers"
- v-model:description.capitalize
- props: ['description', 'descriptionModifiers'],
- :value="description"
- @input="$emit('update:description', $event.target.value)"
- console.log(this.descriptionModifiers) // { capitalize: true }
-
-
- Using our date-picker component example from the previous section, in the event we need to apply all non-prop attributes to the
input
element rather than the rootdiv
element, this can be accomplished by using thev-bind
shortcut. - inheritAttrs: false,
- v-bind="$attrs"
- data-status="activated"
- data-status="activated"
- @click="changeValue"
- v-bind="$attrs"
-
-
- Vue also allows you to register your own custom directives
- the primary form of code reuse and abstraction is components - however, there may be cases where you need some low-level DOM access on plain elements, and this is where custom directives would still be useful.
- if you haven't clicked on anything else since visiting this page, the input above should be focused now. Also, you can click on the
Rerun
button and input will be focused. - If you want to register a directive locally instead, components also accept a
directives
option: - created
- beforeMount
- mounted
- beforeUpdate
- updated
- beforeUnmount
- unmounted
- Directive arguments can be dynamic. For example, in
v-mydirective:[argument]="value"
, theargument
can be updated based on data properties in our component instance! - 'pin'
- mounted(el, binding) { el.style.position = 'fixed' // binding.value is the value we pass to directive - in this case, it's 200 el.style.top = binding.value + 'px' }
- // binding.arg is an argument we pass to directive const s = binding.arg || 'top'
- If your directive needs multiple values, you can also pass in a JavaScript object literal.
- "{ color: 'white', text: 'hello!' }"
-
-
- Hook functions with the same name are merged into an array so that all of them will be called.
-
-
- When using the Composition API, the concept of reactive refs and template refs are unified. In order to obtain a reference to an in-template element or component instance, we can declare a ref as usual and return it from setup():
- ref="root"
- const root = ref(null)
- root.value
- return { root }
- Here we are exposing
root
on the render context and binding it to the div as its ref viaref="root"
- if a VNode's
ref
key corresponds to a ref on the render context, the VNode's corresponding element or component instance will be assigned to the value of that ref. This is performed during the Virtual DOM mount / patch process, so template refs will only get assigned values after the initial render. - Refs used as templates refs behave just like any other refs: they are reactive and can be passed into (or returned from) composition functions.
- const root = ref(null)
- :ref="el => { if (el) divs[i] = el }"
- const list = reactive([1, 2, 3])
- const divs = ref([])
- return { list, divs }
- // This effect runs before the DOM is updated, and consequently, // the template ref does not hold a reference to the element yet. console.log(root.value) // => null
- Therefore, watchers that use template refs should be defined with the
flush: 'post'
option. - This will run the effect after the DOM has been updated and ensure that the template ref stays in sync with the DOM and references the correct element.
- { flush: 'post' }
-
-
Dynamic & Async Components | Vue.js
- You'll notice that if you select a post, switch to the Archive tab, then switch back to Posts, it's no longer showing the post you selected
- Recreating dynamic components is normally useful behavior, but in this case, we'd really like those tab component instances to be cached once they're created for the first time. To solve this problem, we can wrap our dynamic component with a
<keep-alive>
element: - <keep-alive>
- </keep-alive>
- In large applications, we may need to divide the app into smaller chunks and only load a component from the server when it's needed.
- defineAsyncComponent
- defineAsyncComponent
- () => new Promise((resolve, reject) => { resolve({ template: '<div>I am async!</div>' }) })
- his method accepts a factory function returning a
Promise
- Promise's
resolve
callback should be called when you have retrieved your component definition from the server. - efineAsyncComponent(() => import('./components/AsyncComponent.vue') )
- AsyncComponent: defineAsyncComponent(() => import('./components/AsyncComponent.vue') )
- The async component can opt-out of
Suspense
control and let the component always control its own loading state by specifyingsuspensible: false
in its options.
-
-
- when we need to pass data from the parent to child component, we use props.
- the structure where you have some deeply nested components and you only need something from the parent component in the deep nested child.
- you still need to pass the prop down the whole component chain which might be annoying.
- we can use the
provide
andinject
pair - Parent components can serve as dependency provider for all its children, regardless how deep the component hierarchy is
- parent component has a
provide
option to provide data and child component has aninject
option to start using this data. - If we want to pass the length of todo-items directly to
TodoListStatistics
, we would pass the prop down the hierarchy:TodoList
->TodoListFooter
->TodoListStatistics
. With provide/inject approach, we can do this directly: - provide: { user: 'John Doe' },
- inject: ['user'],
- console.log(`Injected property: ${this.user}`) // > Injected property: John Doe
- To access component instance properties, we need to convert
provide
to be a function returning an object - return { todoLength: this.todos.length }
- parent components don’t need to know which descendants use the properties it provides
- child components don’t need to know where injected properties are coming from
- if we change the list of
todos
, this change won't be reflected in the injectedtodoLength
property. This is becauseprovide/inject
bindings are not reactive by default. - We can change this behavior by passing a
ref
property orreactive
object toprovide
- return { todoLength: Vue.computed(() => this.todos.length) }
- inject: ['todoLength'],
- console.log(`Injected property: ${this.todoLength.value}`) // > Injected property: 5
- any change to
todos.length
will be reflected correctly in the components, wheretodoLength
is injected.
-
-
- Everything in the parent template is compiled in parent scope; everything in the child template is compiled in the child scope
- There are times when it's useful to have multiple slots.
- the
<slot>
element has a special attribute,name
, which can be used to assign a unique ID to different slots so you can determine where content should be rendered: - To provide content to named slots, we need to use the
v-slot
directive on a<template>
element, providing the name of the slot asv-slot
's argument: -
- Scoped Slots
- child 에서 넘겨주는 값들을 parent에서 받아서 처리하는 경우에 사용.
- it's useful for slot content to have access to data only available in the child component.
- todo-list
- <todo-list> <i class="fas fa-check"></i> <span class="green">{{ item }}</span> </todo-list>
- parent component
- <slot :item="item"></slot>
- <slot :item="item" :index="index" :another-attribute="anotherAttribute"></slot>
- Attributes bound to a
<slot>
element are called slot props. - <template v-slot:default="slotProps">
- { slotProps.item }}
- </template>
- we've chosen to name the object containing all our slot props
slotProps
, but you can use any name you like. - v-slot:default
- v-slot
- Note that the abbreviated syntax for default slot cannot be mixed with named slots, as it would lead to scope ambiguity:
- <!-- INVALID, will result in warning -->
- Whenever there are multiple slots, use the full
<template>
based syntax for all slots: - { item }
- {{ item }}
- This can make the template much cleaner, especially when the slot provides many props. It also opens other possibilities, such as renaming props, e.g.
item
totodo
: - { item: todo }
- {{ todo }}
- item = 'Placeholder'
- 함수 파라미터의 기본값처럼 사용.
- [dynamicSlotName]
- Similar to
v-on
andv-bind
,v-slot
also has a shorthand, replacing everything before the argument (v-slot:
) with the special symbol#
- #header
- #default
- #footer
- <!-- This will trigger a warning -->
- #default="{ item }"
-
-
-
ref
— Takes an inner value and returns a reactive and mutable ref object. The ref object has a single property.value
that points to the inner value -
reactive
— Returns a reactive copy of the object. The reactive conversion is “deep” — it affects all nested properties. -
computed
method — Takes a getter function and returns an immutable reactive ref object for the returned value from the getter. - To apply and automatically re-apply a side effect based on reactive state, we can use the
effect
method.
-
-
Vue 3 Composition API: Ref vs Reactive - Dan Vega
- We should just use
ref()
for primitives andreactive()
for objects. - There is a
toRefs()
method that will convert a reactive object to a plain object, where each property on the resulting object is a ref pointing to the corresponding property in the original object.
-
댓글