Last active
April 30, 2017 14:55
-
-
Save pjchender/063aff2b057374e3eac4eb4f6ebb89ec to your computer and use it in GitHub Desktop.
[Vue] 生命週期與 AJAX 使用說明
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<title>Demo Vue</title> | |
<script src="https://unpkg.com/[email protected]/dist/vue.js"></script> | |
<script src="https://unpkg.com/[email protected]/dist/axios.js"></script> | |
</head> | |
<body> | |
<div id="app"> | |
<h1>{{ posts[currentId].title }}</h1> | |
<h2>{{ posts[currentId].body }}</h2> | |
<h3>{{ id }}</h3> | |
</div> | |
<script> | |
const vm = new Vue({ | |
el: '#app', | |
data: { | |
// 這時候因為 posts 沒有資料,但是 render 要顯示,所以會出現錯誤 | |
// TypeError: Cannot read property 'title' of undefined | |
currentId: 0, | |
body: '', | |
title: '', | |
posts: [] | |
}, | |
computed: { | |
// computed 的屬性在 vm 初次 create 時不會先被執行一次, | |
id () { | |
console.log('id computed') | |
return `post${this.currentId}` | |
} | |
}, | |
methods: { | |
getCurrentId () { | |
console.log('getCurrentId', this.currentId) | |
} | |
}, | |
beforeCreate () { | |
// 在 berforeCrate 資料沒 bind 上 vm,所以 this 拿不到資料 | |
console.log('beforeCreate') | |
}, | |
created () { | |
// created 之後可以 data bind 上 vm ,可以透過 this 拿到資料 | |
console.log('created') | |
let self = this | |
// 這裡面用 AJAX 取得資料 | |
axios({ | |
method: 'get', | |
url: 'https://jsonplaceholder.typicode.com/posts/' | |
}) | |
.then(function (response) { | |
// 把 AJAX 取得的資料代入 Vue 中 | |
self.posts = response.data | |
console.log('getResponse') | |
}) | |
.catch(function (error) { | |
console.log('err', error) | |
}) | |
}, | |
beforeMount () { | |
console.log('beforeMount') | |
}, | |
mounted () { | |
// vm 初次 create 時,會從 beforeCreate 執行到這裡(mounted) | |
console.log('mounted') | |
}, | |
beforeUpdate () { | |
console.log('beforeUpdate') | |
}, | |
updated () { | |
console.log('updated') | |
} | |
}) | |
</script> | |
</body> | |
</html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<title>Demo Vue</title> | |
<script src="https://unpkg.com/[email protected]/dist/vue.js"></script> | |
<script src="https://unpkg.com/[email protected]/dist/axios.js"></script> | |
</head> | |
<body> | |
<div id="app"> | |
<!-- title 和 body 是透過 computed 取得, | |
- 使得 computed 會在 beforeMount 和 mounted 被觸發, | |
- 但是這時候 this.posts 仍然還沒有資料 | |
--> | |
<h1>{{ title }}</h1> | |
<h2>{{ body }}</h2> | |
<h3>{{ id }}</h3> | |
</div> | |
<script> | |
const vm = new Vue({ | |
el: '#app', | |
data: { | |
// 這時候因為 posts 沒有資料,但是 render 要顯示,所以會出現錯誤 | |
// TypeError: Cannot read property 'title' of undefined | |
currentId: 0, | |
posts: [] | |
}, | |
computed: { | |
// computed 的屬性在 vm 初次 create 時不會先被執行一次, | |
id () { | |
console.log('id computed') | |
return `post${this.currentId}` | |
}, | |
/** | |
* 因為在 template 中有 {{ title }} | |
* 促使 computed 在 beforeMount 和 mounted 之間執行 | |
* 但這時候 this.posts 仍沒有資料,出現錯誤 | |
* Error in render function: "TypeError: Cannot read property 'title' of undefined" | |
**/ | |
title () { | |
console.log('title computed') | |
return this.posts[this.currentId].title | |
}, | |
body () { | |
console.log('body computed') | |
return this.posts[this.currentId].body | |
} | |
}, | |
methods: { | |
getCurrentId () { | |
console.log('getCurrentId', this.currentId) | |
} | |
}, | |
beforeCreate () { | |
// 在 berforeCrate 資料沒 bind 上 vm,所以 this 拿不到資料 | |
console.log('beforeCreate') | |
}, | |
created () { | |
// created 之後可以 data bind 上 vm ,可以透過 this 拿到資料 | |
console.log('created') | |
let self = this | |
// 這裡面用 AJAX 取得資料 | |
axios({ | |
method: 'get', | |
url: 'https://jsonplaceholder.typicode.com/posts/' | |
}) | |
.then(function (response) { | |
// 把 AJAX 取得的資料代入 Vue 中 | |
self.posts = response.data | |
console.log('getResponse') | |
}) | |
.catch(function (error) { | |
console.log('err', error) | |
}) | |
}, | |
beforeMount () { | |
console.log('beforeMount') | |
}, | |
mounted () { | |
// vm 初次 create 時,會從 beforeCreate 執行到這裡(mounted) | |
console.log('mounted') | |
}, | |
beforeUpdate () { | |
console.log('beforeUpdate') | |
}, | |
updated () { | |
console.log('updated') | |
} | |
}) | |
</script> | |
</body> | |
</html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<title>Demo Vue</title> | |
<script src="https://unpkg.com/[email protected]/dist/vue.js"></script> | |
<script src="https://unpkg.com/[email protected]/dist/axios.js"></script> | |
</head> | |
<body> | |
<div id="app"> | |
<h1>{{ title }}</h1> | |
<h2>{{ body }}</h2> | |
<h3>{{ id }}</h3> | |
</div> | |
<script> | |
const vm = new Vue({ | |
el: '#app', | |
data: { | |
currentId: 0, | |
posts: [], | |
title: '', | |
body: '' | |
}, | |
computed: { | |
// 除非有需要,否則 computed 的屬性在 vm 初次 create 時不會先被執行一次 | |
// 如果有需要,則 computed 會在 beforeMound 和 mounted 之間執行 | |
id () { | |
console.log('id computed') | |
return `post${this.currentId}` | |
} | |
}, | |
methods: { | |
getCurrentId () { | |
console.log('getCurrentId', this.currentId) | |
} | |
}, | |
beforeCreate () { | |
// 在 berforeCrate 資料沒 bind 上 vm,所以 this 拿不到資料 | |
console.log('beforeCreate') | |
}, | |
created () { | |
// created 之後可以 data bind 上 vm ,可以透過 this 拿到資料 | |
console.log('created') | |
let self = this | |
// 這裡面用 AJAX 取得資料 | |
axios({ | |
method: 'get', | |
url: 'https://jsonplaceholder.typicode.com/posts/' | |
}) | |
.then(function (response) { | |
// 把 AJAX 取得的資料代入 Vue 中 | |
self.posts = response.data | |
// 更新需要初始化的資料 | |
self.title = self.posts[self.currentId].title | |
self.body = self.posts[self.currentId].body | |
console.log('getResponse') | |
}) | |
.catch(function (error) { | |
console.log('err', error) | |
}) | |
}, | |
beforeMount () { | |
console.log('beforeMount') | |
}, | |
mounted () { | |
// vm 初次 create 時,會從 beforeCreate 執行到這裡(mounted) | |
console.log('mounted') | |
}, | |
beforeUpdate () { | |
console.log('beforeUpdate') | |
}, | |
updated () { | |
console.log('updated') | |
} | |
}) | |
</script> | |
</body> | |
</html> |
生命週期基本概念
created
: 一般會把 AJAX 取得的資料的過程寫在 created
的時候,在這把取得的資料存到 vm,並且更新相關需要透過 AJAX 資料才能正確初始化的資料。
beforeMount
: 這時候還沒有 $parent ,組件還沒綁上去
mounted
: 的時候則可以開始綁事件,上場,有可能是進到 document 或其他的 component 中
beforeDestroy
: 要把自己加上的一些事件清除〈例如,requestAnimatinoFrame〉,還可以拿到 this。
destroyed
: 已經拿不到 this
[示範] 程式碼與畫面
相關事件執行時間
- vm 的 data 要在
created
後才會 bind 上去,因此要透過this
使用 vm 內的 data 或 vm 內的 methods 時,需要在created
之後才可以取得this
。 - 一般 vm 初次建立時,生命週期會從
beforeCreate
到mounted
,不會自動進入beforeUpdate
。 - 如果在 created 之後有更新畫面資料的內容,將會促發進入
beforeUpdate
和updated
的 hook。 - 除非相關的資料內容有更新,否則 computed 的屬性在 vm 初次 create 時不會先被執行一次;如果有需要,例如畫面
載入時要 render 被 computed 的屬性{{ id }}
,則 computed 會在 beforeMound 和 mounted 之間執行
const vm = new Vue({
el: '#app',
data: {
currentId: 0,
posts: []
},
computed: {
// 除非有需要,否則 computed 的屬性在 vm 初次 create 時不會先被執行一次
// 若有需要(例如畫面要 render {{ id }}),那麼會在 beforeMount 和 mounted 之間執行 computed
id () {
console.log('id computed')
return `post${this.currentId}`
},
title () {
console.log('title computed')
return this.posts[this.currentId].title
},
body () {
console.log('body computed')
return this.posts[this.currentId].body
}
},
methods: {
getCurrentId () {
console.log('getCurrentId', this.currentId)
}
},
beforeCreate () {
// 在 berforeCrate 資料沒 bind 上 vm,所以 this 拿不到資料
console.log('beforeCreate')
},
created () {
// created 之後可以 data bind 上 vm ,可以透過 this 拿到資料
console.log('created')
let self = this
// 這裡面用 AJAX 取得資料
axios({
method: 'get',
url: 'https://jsonplaceholder.typicode.com/posts/'
})
.then(function (response) {
// **把 AJAX 取得的資料代入 Vue 中**
self.posts = response.data
console.log('getResponse')
})
.catch(function (error) {
console.log('err', error)
})
},
beforeMount () {
console.log('beforeMount')
},
mounted () {
// **vm 初次 create 時,會從 beforeCreate 執行到這裡(mounted)**
console.log('mounted')
},
beforeUpdate () {
console.log('beforeUpdate')
},
updated () {
console.log('updated')
}
})
Vue Life Cycle Map
搭配 AJAX 較好的使用方法
在 template 中寫每次 render 時要顯示的資料
<div id="app">
<h1>{{ title }}</h1>
<h2>{{ body }}</h2>
<h3>{{ id }}</h3>
</div>
把 template 有用到的 data 直接寫到 vm.data 中
- 在 created 拿到 request 回來的資料後,若有需要,把 request 取得的資料寫入 vm.data 中
- 更新需要透過 AJAX 取的資料後,才能初始化的資料。這時候因為我們有更新資料的關係(原本在 data 已經有給值),因此 vm 在建立時,除了從
beforeCreate
跑到mounted
之外,會進一步促發beforeUpdate
和updated
的 hook
const vm = new Vue({
el: '#app',
data: {
currentId: 0,
posts: [],
title: '',
body: ''
},
// ...
created () {
// created 之後可以 data bind 上 vm ,可以透過 this 拿到資料
console.log('created')
let self = this
// 這裡面用 AJAX 取得資料
axios({
method: 'get',
url: 'https://jsonplaceholder.typicode.com/posts/'
})
.then(function (response) {
// STEP1: 把 AJAX 取得的資料代入 Vue 中
self.posts = response.data
// STEP2: 更新需要透過 AJAX 資料才能初始化的資料,如此將進一步促發 `beforeUpdate` 和 `updated`
self.title = self.posts[self.currentId].title
self.body = self.posts[self.currentId].body
console.log('getResponse')
})
.catch(function (error) {
console.log('err', error)
})
}
})
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
rendor-error-1.html
如果我們一開始就在 template 中試圖 render 靠 AJAX 取得的資料
<h1>{{ posts[currentId].title }}</h1>
,那麼這時候因為 this.posts 還沒有資料,所以會出現錯誤TypeError: Cannot read property 'title' of undefined
;但如果我們接著在created
的時候把 AJAX 取得的資料給入this.posts
時,virtual DOM 會 re-render,此時會出現beforeUpdate
和updated
,因此資料雖然會顯示,但初次 render 畫面時會出現 Error。render-error-2.html
另一種情況是,我把需要透過 AJAX 後才能取得的 data 寫在 computed 和 template 中,例如,
<h1>{{ title }}</h1>
,在 computed 中則包含title(){ return this.posts[this.currentId].title }
。這樣做的話,會使得 vm 在beforeMount
和mounted
之前時,因為要 render 出{{ title }}
,進而使的促發computed
的執行,但是這時候 AJAX 的資料仍然還沒回來,this.posts 還是沒有內容,因此一樣會出現錯誤Error in render function: "TypeError: Cannot read property 'title' of undefined"