mirror of
https://github.com/tenrok/vue-meta.git
synced 2026-06-20 14:20:33 +03:00
Merge pull request #18 from declandewet/watcher-logic
circumvent need to call refresh() after async actions
This commit is contained in:
@@ -681,38 +681,28 @@ Easy. Instead of defining `metaInfo` as an object, define it as a function and a
|
|||||||
|
|
||||||
## How do I populate `metaInfo` from the result of an asynchronous action?
|
## How do I populate `metaInfo` from the result of an asynchronous action?
|
||||||
|
|
||||||
`vue-meta` exposes a method called `refresh` on the client-side that allows you to trigger an update at any given point in time.
|
`vue-meta` will do this for you automatically when your component state changes.
|
||||||
|
|
||||||
In the same way you access `$meta().inject()` on the server, you can access `$meta().refresh()`.
|
Just make sure that you're using the function form of `metaInfo`:
|
||||||
|
|
||||||
For example, if you're using Vuex and you have an action that fetches a `post` asynchronously, you should ensure that it returns a promise so that you are notified when the fetching is complete:
|
|
||||||
|
|
||||||
```js
|
```js
|
||||||
{
|
{
|
||||||
actions: {
|
data () {
|
||||||
async fetchPost ({ commit }, payload) {
|
return {
|
||||||
const post = yield db.fetch('posts', payload.postId)
|
title: 'Foo Bar Baz'
|
||||||
commit('fetchedPost', post)
|
}
|
||||||
|
}
|
||||||
|
metaInfo () {
|
||||||
|
return {
|
||||||
|
title: this.title
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Then in your component, you can call `refresh()` to trigger an update once the fetch is complete:
|
Check out the [vuex-async](https://github.com/declandewet/vue-meta/tree/master/examples/vuex-async) example for a far more detailed demonstration if you have doubts.
|
||||||
|
|
||||||
```js
|
Credit & Thanks for this feature goes to [Sébastien Chopin](https://github.com/Atinux).
|
||||||
{
|
|
||||||
beforeMount () {
|
|
||||||
const postId = this.$router.params.id
|
|
||||||
this.$store.dispatch('fetchPost', { postId })
|
|
||||||
.then(() => this.$meta().refresh())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Just make sure that whatever data source you're using (`store` if you're using Vuex, component `data` otherwise) has some sane defaults set so Vue doesn't complain about `null` property accessors.
|
|
||||||
|
|
||||||
Check out the [vuex-async](https://github.com/declandewet/vue-meta/tree/master/examples/vuex-async) example for a far more detailed demonstration of how this works.
|
|
||||||
|
|
||||||
# Examples
|
# Examples
|
||||||
|
|
||||||
|
|||||||
@@ -63,15 +63,10 @@ export default new Vuex.Store({
|
|||||||
actions: {
|
actions: {
|
||||||
getPost ({ commit }, payload) {
|
getPost ({ commit }, payload) {
|
||||||
commit('loadingState', { isLoading: true })
|
commit('loadingState', { isLoading: true })
|
||||||
// we have to return a promise from this action so we know
|
setTimeout(() => {
|
||||||
// when it is finished
|
commit('getPost', payload)
|
||||||
return new Promise((resolve) => {
|
commit('loadingState', { isLoading: false })
|
||||||
setTimeout(() => {
|
}, 2000)
|
||||||
commit('getPost', payload)
|
|
||||||
resolve()
|
|
||||||
}, 2000)
|
|
||||||
})
|
|
||||||
.then(() => commit('loadingState', { isLoading: false }))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -18,11 +18,7 @@
|
|||||||
name: 'post',
|
name: 'post',
|
||||||
beforeMount () {
|
beforeMount () {
|
||||||
const { slug } = this.$route.params
|
const { slug } = this.$route.params
|
||||||
// since fetching a post is asynchronous,
|
|
||||||
// we need to call `this.$meta().refresh()`
|
|
||||||
// to update the meta info
|
|
||||||
this.$store.dispatch('getPost', { slug })
|
this.$store.dispatch('getPost', { slug })
|
||||||
.then(() => this.$meta().refresh())
|
|
||||||
},
|
},
|
||||||
computed: mapGetters([
|
computed: mapGetters([
|
||||||
'isLoading',
|
'isLoading',
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
/**
|
||||||
|
* Performs a batched update. Uses requestAnimationFrame to prevent
|
||||||
|
* calling a function too many times in quick succession.
|
||||||
|
* You need to pass it an ID (which can initially be `null`),
|
||||||
|
* but be sure to overwrite that ID with the return value of batchUpdate.
|
||||||
|
*
|
||||||
|
* @param {(null|Number)} id - the ID of this update
|
||||||
|
* @param {Function} callback - the update to perform
|
||||||
|
* @return {Number} id - a new ID
|
||||||
|
*/
|
||||||
|
export default function batchUpdate (id, callback) {
|
||||||
|
window.cancelAnimationFrame(id)
|
||||||
|
return window.requestAnimationFrame(() => {
|
||||||
|
id = null
|
||||||
|
callback()
|
||||||
|
})
|
||||||
|
}
|
||||||
+21
-7
@@ -1,5 +1,6 @@
|
|||||||
import assign from 'object-assign'
|
import assign from 'object-assign'
|
||||||
import $meta from './$meta'
|
import $meta from './$meta'
|
||||||
|
import batchUpdate from '../client/batchUpdate'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
VUE_META_KEY_NAME,
|
VUE_META_KEY_NAME,
|
||||||
@@ -33,18 +34,31 @@ export default function VueMeta (Vue, options = {}) {
|
|||||||
Vue.prototype.$meta = $meta(options)
|
Vue.prototype.$meta = $meta(options)
|
||||||
|
|
||||||
// store an id to keep track of DOM updates
|
// store an id to keep track of DOM updates
|
||||||
let requestId = null
|
let batchID = null
|
||||||
|
|
||||||
// watch for client side component updates
|
// watch for client side component updates
|
||||||
Vue.mixin({
|
Vue.mixin({
|
||||||
|
beforeCreate () {
|
||||||
|
// coerce function-style metaInfo to a computed prop so we can observe
|
||||||
|
// it on creation
|
||||||
|
if (typeof this.$options[options.keyName] === 'function') {
|
||||||
|
this.$options.computed.$metaInfo = this.$options[options.keyName]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created () {
|
||||||
|
// if computed $metaInfo exists, watch it for updates & trigger a refresh
|
||||||
|
// when it changes (i.e. automatically handle async actions that affect metaInfo)
|
||||||
|
// credit for this suggestion goes to [Sébastien Chopin](https://github.com/Atinux)
|
||||||
|
if (this.$metaInfo) {
|
||||||
|
this.$watch('$metaInfo', () => {
|
||||||
|
// batch potential DOM updates to prevent extraneous re-rendering
|
||||||
|
batchID = batchUpdate(batchID, () => this.$meta().refresh())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
beforeMount () {
|
beforeMount () {
|
||||||
// batch potential DOM updates to prevent extraneous re-rendering
|
// batch potential DOM updates to prevent extraneous re-rendering
|
||||||
window.cancelAnimationFrame(requestId)
|
batchID = batchUpdate(batchID, () => this.$meta().refresh())
|
||||||
|
|
||||||
requestId = window.requestAnimationFrame(() => {
|
|
||||||
requestId = null
|
|
||||||
this.$meta().refresh()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user