Commit abe0093a authored by Evan You's avatar Evan You

simplify store actions

parent 74736699
...@@ -27,7 +27,6 @@ ...@@ -27,7 +27,6 @@
<script> <script>
import Spinner from './Spinner.vue' import Spinner from './Spinner.vue'
import NewsItem from './NewsItem.vue' import NewsItem from './NewsItem.vue'
import { fetchInitialData } from '../store'
export default { export default {
name: 'NewsList', name: 'NewsList',
...@@ -76,7 +75,9 @@ export default { ...@@ -76,7 +75,9 @@ export default {
methods: { methods: {
loadItems (to, from) { loadItems (to, from) {
this.loading = true this.loading = true
fetchInitialData(this.type).then(() => { this.$store.dispatch('FETCH_DATA_FOR_TYPE', {
type: this.type
}).then(() => {
if (this.page < 0 || this.page > this.maxPage) { if (this.page < 0 || this.page > this.maxPage) {
this.$router.replace(`/${this.type}/1`) this.$router.replace(`/${this.type}/1`)
return return
......
...@@ -8,8 +8,8 @@ export default context => { ...@@ -8,8 +8,8 @@ export default context => {
// call prefetch hooks on components matched by the route // call prefetch hooks on components matched by the route
const s = isDev && Date.now() const s = isDev && Date.now()
return Promise.all(router.getMatchedComponents().map(component => { return Promise.all(router.getMatchedComponents().map(component => {
if (component.prefetch) { if (component.preFetch) {
return component.prefetch(store) return component.preFetch(store)
} }
})).then(() => { })).then(() => {
isDev && console.log(`data pre-fetch: ${Date.now() - s}ms`) isDev && console.log(`data pre-fetch: ${Date.now() - s}ms`)
......
...@@ -36,7 +36,7 @@ function createServerSideAPI () { ...@@ -36,7 +36,7 @@ function createServerSideAPI () {
// warm the cache every 15 min, since the front page changes quite often // warm the cache every 15 min, since the front page changes quite often
warmCache() warmCache()
function warmCache () { function warmCache () {
fetchItems((api.__topIds__ || []).slice(0, 30)) fetchItems((api.__ids__.top || []).slice(0, 30))
setTimeout(warmCache, 1000 * 60 * 15) setTimeout(warmCache, 1000 * 60 * 15)
} }
...@@ -60,7 +60,7 @@ export function fetchIdsByType (type) { ...@@ -60,7 +60,7 @@ export function fetchIdsByType (type) {
export function watchTopIds (cb) { export function watchTopIds (cb) {
api.child(`topstories`).on('value', snapshot => { api.child(`topstories`).on('value', snapshot => {
const ids = snapshot.val() const ids = snapshot.val()
api.__topIds__ = ids api.__ids__ && (api.__ids__.top = ids)
cb(ids) cb(ids)
}) })
} }
......
...@@ -22,16 +22,12 @@ const store = new Vuex.Store({ ...@@ -22,16 +22,12 @@ const store = new Vuex.Store({
}, },
actions: { actions: {
FETCH_ACTIVE_IDS: ({ commit, state }) => { FETCH_DATA_FOR_TYPE: ({ commit, dispatch, state, getters }, { type }) => {
const type = state.activeType commit('SET_ACTIVE_TYPE', { type })
return fetchIdsByType(type).then(ids => { return fetchIdsByType(type)
commit('SET_IDS', { type, ids }) .then(ids => commit('SET_LIST', { type, ids }))
}) .then(() => fetchItems(getters.activeIds.filter(id => !state.items[id])))
}, .then(items => commit('SET_ITEMS', { items }))
FETCH_ACTIVE_ITEMS: ({ commit, state, getters }) => {
return fetchItems(getters.activeIds).then(items => {
commit('SET_ITEMS', { items })
})
} }
}, },
...@@ -39,12 +35,16 @@ const store = new Vuex.Store({ ...@@ -39,12 +35,16 @@ const store = new Vuex.Store({
SET_ACTIVE_TYPE: (state, { type }) => { SET_ACTIVE_TYPE: (state, { type }) => {
state.activeType = type state.activeType = type
}, },
SET_IDS: (state, { type, ids }) => {
SET_LIST: (state, { type, ids }) => {
state.lists[type] = ids state.lists[type] = ids
}, },
SET_ITEMS: (state, { items }) => { SET_ITEMS: (state, { items }) => {
items.forEach(item => { items.forEach(item => {
if (item) {
Vue.set(state.items, item.id, item) Vue.set(state.items, item.id, item)
}
}) })
} }
}, },
...@@ -61,25 +61,11 @@ const store = new Vuex.Store({ ...@@ -61,25 +61,11 @@ const store = new Vuex.Store({
return [] return []
} }
}, },
activeItems (state, getters) { activeItems (state, getters) {
return getters.activeIds.map(id => state.items[id]).filter(_ => _) return getters.activeIds.map(id => state.items[id]).filter(_ => _)
} }
} }
}) })
// watch for realtime top IDs updates on the client
if (typeof window !== 'undefined') {
watchTopIds(ids => {
store.commit('SET_IDS', { type: 'top', ids })
store.dispatch('FETCH_ACTIVE_ITEMS')
})
}
export function fetchInitialData (type) {
store.commit('SET_ACTIVE_TYPE', { type })
return store
.dispatch('FETCH_ACTIVE_IDS')
.then(() => store.dispatch('FETCH_ACTIVE_ITEMS'))
}
export default store export default store
import NewsList from '../components/NewsList.vue' import NewsList from '../components/NewsList.vue'
import { fetchInitialData } from '../store'
// factory function for creating root-level list views // factory function for creating root-level list views
// since they share most of the logic except for the type of items to display. // since they share most of the logic except for the type of items to display.
...@@ -9,8 +8,9 @@ export function createListView (type) { ...@@ -9,8 +8,9 @@ export function createListView (type) {
components: { components: {
NewsList NewsList
}, },
prefetch () { // this will be called during SSR to pre-fetch data into the store!
return fetchInitialData(type) preFetch (store) {
return store.dispatch('FETCH_DATA_FOR_TYPE', { type })
}, },
created () { created () {
this.$store.commit('SET_ACTIVE_TYPE', { type }) this.$store.commit('SET_ACTIVE_TYPE', { type })
......
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