Teach the create
option from the very beginning, replacing data
/computed
/methods
:
new Vue({
el: '#app',
create: {
message: 'Vue'
}
})
Demonstrate how create
adds new properties to the instance, which can be accessed in other options on this
and in templates:
new Vue({
el: '#app',
create: {
count: 1
},
onCreated() {
console.log('Count is: ' + this.count)
}
})
<div id="app">
Count is: {{ count }}
</div>
The first time we demonstrate adding a method, just add it to the create
object, which accesses other properties by assigning the Vue instance to a variable:
const app = new Vue({
el: '#app',
create: {
message: 'Hello Vue.js!',
reverseMessage() {
app.message = app.message
.split('')
.reverse()
.join('')
}
}
})
Show how to create computed
properties using Vue.computed
, accessing other properties the same way we did with a method:
const app = new Vue({
el: '#app',
create: {
message: 'Hello',
reversedMessage: Vue.computed(() =>
app.message
.split('')
.reverse()
.join('')
)
}
})
Introduce complex example with watch
, which we demonstrate as an option (we don't need to go into using Vue.watch
inside create
, since it will be useful for organizational purposes far less often):
const app = new Vue({
el: '#app',
create: {
question: '',
answer: 'I cannot give you an answer until you ask a question!',
getAnswer: _.debounce(() => {
if (app.question.indexOf('?') === -1) {
app.answer = 'Questions usually contain a question mark. ;-)'
return
}
app.answer = 'Thinking...'
axios
.get('https://yesno.wtf/api')
.then(response => {
app.answer = _.capitalize(response.data.answer)
})
.catch(error => {
app.answer = 'Error! Could not reach the API. ' + error
})
}), 500)
},
watch: {
question(newQuestion, oldQuestion) {
this.answer = 'Waiting for you to stop typing...'
this.getAnswer()
}
}
})
When we introduce components, we show that create
has to be a function, just as we do currently for data
:
Vue.component('button-counter', {
create() {
return {
count: 0
}
},
template: `
<button v-on:click="count++">
You clicked me {{ count }} times.
</button>
`
})
Demonstrate accessing props
from the create
function when we introduce them:
Vue.component('button-counter', {
props: ['initialCount'],
create(props) {
return {
count: props.initialCount
}
},
template: `
<button v-on:click="count++">
You clicked me {{ count }} times.
</button>
`
})
Explain how the result of Vue.component
is a component definition, not an instance, because components are reusable and can have many instances. That's why in create
, we access other properties from computed properties and functions by assigning the object to a state
variable:
Vue.component('button-counter', {
props: ['initialCount'],
create(props) {
const state = {
count: props.initialCount,
countIncrease: Vue.computed(
() => state.count - props.initialCount
),
incrementCount() {
state.count++
}
}
return state
},
template: `
<button v-on:click="incrementCount">
You clicked me {{ count }}
({{ initialCount }} + {{ countIncrease }})
times.
</button>
`
})
Demonstrate how the other options on a component are the same:
Vue.component('button-counter', {
props: ['initialCount'],
create(props) {
return {
count: props.initialCount
}
},
onCreated() {
console.log('The count is: ' + this.count)
},
watch: {
count(newCount, oldCount) {
console.log('The count changed!')
}
},
template: `
<button v-on:click="count++">
You clicked me {{ count }} times.
</button>
`
})
===
DONE WITH ESSENTIALS
===
Demonstrate that some contextual information is available on the context
object in the create
function and under this.$context
in other options:
Vue.component('button-counter', {
create(props, context) {
return {
map: context.parent.map
}
},
onCreated() {
console.log(this.$context.parent.map)
},
template: '...'
})
Vue.component('some-component', {
create(props, context) {
return {
fooPlusBar: Vue.computed(
() => context.root.foo + context.root.bar
)
}
},
onMounted() {
this.$context.root.baz()
},
template: '...'
})
const root = new Vue({
el: '#app',
create: {
foo: 1,
bar: Vue.computed(() => root.foo * 2),
baz() {
// ...
}
}
})
Vue.component('username-input', {
create(props, context) {
return {
focus() {
context.refs.input.focus()
}
}
},
onCreated() {
console.log(this.$context.refs.input)
},
template: '...'
})
Demonstrate advanced composition by splitting up features into reusable functions, explaining the concept of bindings, reactive objects, when/why each are important to know about, and how to use the standalone function versions of other options such as watch
, onCreated
, etc:
export default getResults => {
const state = reactive({
query: '',
results: [],
run() {
state.results = []
return getResults(state.query).then(results => {
state.results = results
})
}
})
return state
})
import { computed } from 'vue'
import orderBy from 'lodash/orderBy'
export default ({ input, options }) => {
const state = reactive({
input,
options,
selectedOptionIndex: 0,
output: computed(() => {
const selectedOption = state.options[state.selectedOptionIndex]
return orderBy(state.input, ...selectedOption)
})
})
return state
})
<script>
import createSearch from '@features/search'
import createSorting from '@features/sorting'
import axios from 'axios'
import { computed } from 'vue'
export default {
create() {
const productSearch = createSearch({
getResults: query =>
axios
.get('/api/products', { params: { query } })
.then(response => response.data.products)
})
const resultSorting = createSorting({
input: computed(() => productSearch.results),
options: [['averageReviewScore', 'desc'], ['price', 'asc']]
})
return { productSearch, resultSorting }
}
}
</script>
<template>
<input
v-model="productSearch.query"
@keydown.enter="productSearch.run"
/>
<template v-if="resultSorting.output.length > 0">
<SortingOptions
v-model="resultSorting.selectedOptionIndex"
:options="resultSorting.options"
/>
<ProductList :products="resultSorting.output" />
</template>
</template>