Commit 8db2ee92 authored by Evan You's avatar Evan You

realtime updates

parent 55122cae
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
<script> <script>
import Spinner from './Spinner.vue' import Spinner from './Spinner.vue'
import NewsItem from './NewsItem.vue' import NewsItem from './NewsItem.vue'
import { watchList } from '../store/api'
export default { export default {
name: 'NewsList', name: 'NewsList',
...@@ -46,7 +47,9 @@ export default { ...@@ -46,7 +47,9 @@ export default {
loading: false, loading: false,
transition: 'slide-left', transition: 'slide-left',
// if this is the initial render, directly render with the store state // if this is the initial render, directly render with the store state
// otherwise this is a page switch, start with blank and wait for data load // otherwise this is a page switch, start with blank and wait for data load.
// we need these local state so that we can precisely control the timing
// of the transitions.
displayedPage: isInitialRender ? Number(this.$store.state.route.params.page) || 1 : -1, displayedPage: isInitialRender ? Number(this.$store.state.route.params.page) || 1 : -1,
displayedItems: isInitialRender ? this.$store.getters.activeItems : [] displayedItems: isInitialRender ? this.$store.getters.activeItems : []
} }
...@@ -69,6 +72,16 @@ export default { ...@@ -69,6 +72,16 @@ export default {
if (this.$root._isMounted) { if (this.$root._isMounted) {
this.loadItems(this.page) this.loadItems(this.page)
} }
this.unwatchList = watchList(this.type, ids => {
this.$store.commit('SET_LIST', { type: this.type, ids })
this.$store.dispatch('FETCH_ACTIVE_ITEMS').then(() => {
this.displayedItems = this.$store.getters.activeItems
})
})
},
destroyed () {
this.unwatchList()
}, },
watch: { watch: {
......
...@@ -71,3 +71,19 @@ export function fetchItem (id, forceRefresh) { ...@@ -71,3 +71,19 @@ export function fetchItem (id, forceRefresh) {
export function fetchItems (ids) { export function fetchItems (ids) {
return Promise.all(ids.map(id => fetchItem(id))) return Promise.all(ids.map(id => fetchItem(id)))
} }
export function watchList (type, cb) {
let first = true
const ref = api.child(`${type}stories`)
const handler = snapshot => {
if (first) {
first = false
} else {
cb(snapshot.val())
}
}
ref.on('value', handler)
return () => {
ref.off('value', handler)
}
}
...@@ -26,8 +26,16 @@ const store = new Vuex.Store({ ...@@ -26,8 +26,16 @@ const store = new Vuex.Store({
commit('SET_ACTIVE_TYPE', { type }) commit('SET_ACTIVE_TYPE', { type })
return fetchIdsByType(type) return fetchIdsByType(type)
.then(ids => commit('SET_LIST', { type, ids })) .then(ids => commit('SET_LIST', { type, ids }))
.then(() => fetchItems(getters.activeIds.filter(id => !state.items[id]))) .then(() => dispatch('FETCH_ACTIVE_ITEMS'))
.then(items => commit('SET_ITEMS', { items })) },
FETCH_ACTIVE_ITEMS: ({ commit, state, getters }) => {
const ids = getters.activeIds.filter(id => !state.items[id])
if (ids.length) {
return fetchItems(ids).then(items => commit('SET_ITEMS', { items }))
} else {
return Promise.resolve()
}
} }
}, },
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment