Skip to content

Commit 01d04ad

Browse files
committed
handle view param changes and user not found
1 parent 8255a01 commit 01d04ad

File tree

7 files changed

+55
-23
lines changed

7 files changed

+55
-23
lines changed

src/entry-client.js

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,17 @@ import Vue from 'vue'
22
import 'es6-promise/auto'
33
import { createApp } from './app'
44

5-
// a global mixin to invoke fetchData on the client
5+
// a global mixin that calls `asyncData` when a route component's params change
66
Vue.mixin({
7-
beforeMount () {
7+
beforeRouteUpdate (to, from, next) {
88
const { asyncData } = this.$options
99
if (asyncData) {
10-
this.dataPromise = asyncData(
11-
this.$store,
12-
this.$route
13-
)
10+
asyncData({
11+
store: this.$store,
12+
route: to
13+
}).then(next)
14+
} else {
15+
next()
1416
}
1517
}
1618
})
@@ -26,6 +28,17 @@ if (window.__INITIAL_STATE__) {
2628
// wait until router has resolved all async before hooks
2729
// and async components...
2830
router.onReady(() => {
31+
// add router hook for handling asyncData
32+
// doing it after initial route is resolved so that we don't double-fetch
33+
// the data that we already have.
34+
router.beforeResolve((to, from, next) => {
35+
Promise.all(router.getMatchedComponents(to).map(c => {
36+
if (c.asyncData) {
37+
return c.asyncData({ store, route: to })
38+
}
39+
})).then(next)
40+
})
41+
2942
// actually mount to DOM
3043
app.$mount('#app')
3144
})

src/entry-server.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,11 @@ export default context => {
2727
// which is resolved when the action is complete and store state has been
2828
// updated.
2929
Promise.all(matchedComponents.map(component => {
30-
return component.asyncData && component.asyncData(
30+
return component.asyncData && component.asyncData({
3131
store,
32-
router.currentRoute,
33-
context
34-
)
32+
route: router.currentRoute,
33+
ssrContext: context
34+
})
3535
})).then(() => {
3636
isDev && console.log(`data pre-fetch: ${Date.now() - s}ms`)
3737
// After all preFetch hooks are resolved, our store is now

src/store/actions.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,6 @@ export default {
4444
FETCH_USER: ({ commit, state }, { id }) => {
4545
return state.users[id]
4646
? Promise.resolve(state.users[id])
47-
: fetchUser(id).then(user => commit('SET_USER', { user }))
47+
: fetchUser(id).then(user => commit('SET_USER', { id, user }))
4848
}
4949
}

src/store/mutations.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export default {
1717
})
1818
},
1919

20-
SET_USER: (state, { user }) => {
21-
Vue.set(state.users, user.id, user)
20+
SET_USER: (state, { id, user }) => {
21+
Vue.set(state.users, id, user || false) /* false means user not found */
2222
}
2323
}

src/views/CreateListView.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ export default function createListView (type) {
1010
return {
1111
name: `${type}-stories-view`,
1212

13-
asyncData (store, route, context) {
13+
asyncData ({ store, ssrContext }) {
1414
return store.dispatch('FETCH_LIST_DATA', { type }).then(() => {
15-
setTitle(camelize(type), context)
15+
setTitle(camelize(type), ssrContext)
1616
})
1717
},
1818

src/views/ItemView.vue

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,20 +46,33 @@ export default {
4646
}
4747
},
4848
49-
asyncData (store, { params: { id }}, context) {
49+
// We only fetch the item itself before entering the view, because
50+
// it might take a long time to load threads with hundreds of comments
51+
// due to how the HN Firebase API works.
52+
asyncData ({ store, route: { params: { id }}, ssrContext }) {
5053
return store.dispatch('FETCH_ITEMS', { ids: [id] }).then(() => {
5154
const item = store.state.items[id]
52-
setTitle(item.title, context)
55+
setTitle(item.title, ssrContext)
5356
})
5457
},
5558
56-
// on the client, fetch all comments
59+
// Fetch comments when mounted on the client
5760
beforeMount () {
58-
this.dataPromise.then(() => {
61+
this.fetchComments()
62+
},
63+
64+
// refetch comments if item changed
65+
watch: {
66+
item: 'fetchComments'
67+
},
68+
69+
methods: {
70+
fetchComments () {
71+
this.loading = true
5972
fetchComments(this.$store, this.item).then(() => {
6073
this.loading = false
6174
})
62-
})
75+
}
6376
}
6477
}
6578

src/views/UserView.vue

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<template>
22
<div class="user-view">
3-
<spinner :show="!user"></spinner>
3+
<spinner :show="!userLoaded"></spinner>
44
<template v-if="user">
55
<h1>User : {{ user.id }}</h1>
66
<ul class="meta">
@@ -13,6 +13,9 @@
1313
<a :href="'https://news.ycombinator.com/threads?id=' + user.id">comments</a>
1414
</p>
1515
</template>
16+
<template v-else-if="user === false">
17+
<h1>User not found.</h1>
18+
</template>
1619
</div>
1720
</template>
1821

@@ -27,13 +30,16 @@ export default {
2730
computed: {
2831
user () {
2932
return this.$store.state.users[this.$route.params.id]
33+
},
34+
userLoaded () {
35+
return this.$route.params.id in this.$store.state.users
3036
}
3137
},
3238
33-
asyncData (store, { params: { id }}, context) {
39+
asyncData ({ store, route: { params: { id }}, ssrContext }) {
3440
return store.dispatch('FETCH_USER', { id }).then(() => {
3541
const user = store.state.users[id]
36-
setTitle(user.id, context)
42+
setTitle(user ? user.id : 'User not found', ssrContext)
3743
})
3844
}
3945
}

0 commit comments

Comments
 (0)