Commit f519772c authored by Evan You's avatar Evan You

item view

parent e9257b85
<template> <template>
<li class="news-item">{{ item.title }}</li> <li class="news-item">
<a :href="item.url" target="_blank">{{ item.title }}</a><br>
<router-link :to="'/item/' + item.id">
{{ item.descendants }} comments
</router-link>
| by
<router-link :to="'/user/' + item.by">
{{ item.by }}
</router-link>
</li>
</template> </template>
<script> <script>
...@@ -12,4 +21,5 @@ export default { ...@@ -12,4 +21,5 @@ export default {
<style lang="stylus"> <style lang="stylus">
.news-item .news-item
background-color #fff background-color #fff
margin 10px 0
</style> </style>
...@@ -16,8 +16,8 @@ ...@@ -16,8 +16,8 @@
<transition :name="transition"> <transition :name="transition">
<div class="news-list" :key="displayedPage"> <div class="news-list" :key="displayedPage">
<transition-group tag="ul" name="item"> <transition-group tag="ul" name="item">
<news-item v-for="item in displayedItems" :key="item.id" :item="item"> <item v-for="item in displayedItems" :key="item.id" :item="item">
</news-item> </item>
</transition-group> </transition-group>
</div> </div>
</transition> </transition>
...@@ -26,15 +26,15 @@ ...@@ -26,15 +26,15 @@
<script> <script>
import Spinner from './Spinner.vue' import Spinner from './Spinner.vue'
import NewsItem from './NewsItem.vue' import Item from './Item.vue'
import { watchList } from '../store/api' import { watchList } from '../store/api'
export default { export default {
name: 'NewsList', name: 'item-list',
components: { components: {
Spinner, Spinner,
NewsItem Item
}, },
props: { props: {
...@@ -68,20 +68,20 @@ export default { ...@@ -68,20 +68,20 @@ export default {
} }
}, },
mounted () { beforeMount () {
if (this.$root._isMounted) { if (this.$root._isMounted) {
this.loadItems(this.page) this.loadItems(this.page)
} }
// watch the current list for realtime updates // watch the current list for realtime updates
this.unwatchList = watchList(this.type, ids => { this.unwatchList = watchList(this.type, ids => {
this.$store.commit('SET_LIST', { type: this.type, ids }) this.$store.commit('SET_LIST', { type: this.type, ids })
this.$store.dispatch('FETCH_ACTIVE_ITEMS').then(() => { this.$store.dispatch('ENSURE_ACTIVE_ITEMS').then(() => {
this.displayedItems = this.$store.getters.activeItems this.displayedItems = this.$store.getters.activeItems
}) })
}) })
}, },
destroyed () { beforeDestroy () {
this.unwatchList() this.unwatchList()
}, },
...@@ -94,7 +94,7 @@ export default { ...@@ -94,7 +94,7 @@ export default {
methods: { methods: {
loadItems (to = this.page, from = -1) { loadItems (to = this.page, from = -1) {
this.loading = true this.loading = true
this.$store.dispatch('FETCH_DATA_FOR_TYPE', { this.$store.dispatch('FETCH_LIST_DATA', {
type: this.type type: this.type
}).then(() => { }).then(() => {
if (this.page < 0 || this.page > this.maxPage) { if (this.page < 0 || this.page > this.maxPage) {
......
...@@ -4,7 +4,9 @@ import Router from 'vue-router' ...@@ -4,7 +4,9 @@ import Router from 'vue-router'
Vue.use(Router) Vue.use(Router)
import { createListView } from '../views/CreateListView' import { createListView } from '../views/CreateListView'
import About from '../views/About.vue' import ItemView from '../views/ItemView.vue'
import UserView from '../views/UserView.vue'
import AboutView from '../views/AboutView.vue'
export default new Router({ export default new Router({
mode: 'history', mode: 'history',
...@@ -14,7 +16,9 @@ export default new Router({ ...@@ -14,7 +16,9 @@ export default new Router({
{ path: '/show/:page(\\d+)?', component: createListView('show') }, { path: '/show/:page(\\d+)?', component: createListView('show') },
{ path: '/ask/:page(\\d+)?', component: createListView('ask') }, { path: '/ask/:page(\\d+)?', component: createListView('ask') },
{ path: '/job/:page(\\d+)?', component: createListView('job') }, { path: '/job/:page(\\d+)?', component: createListView('job') },
{ path: '/about', component: About }, { path: '/item/:id(\\d+)', component: ItemView },
{ path: '/user/:id', component: UserView },
{ path: '/about', component: AboutView },
{ path: '*', redirect: '/top/1' } { path: '*', redirect: '/top/1' }
] ]
}) })
...@@ -79,14 +79,11 @@ export function watchList (type, cb) { ...@@ -79,14 +79,11 @@ export function watchList (type, cb) {
if (first) { if (first) {
first = false first = false
} else { } else {
console.log(`update for ${type}`)
cb(snapshot.val()) cb(snapshot.val())
} }
} }
console.log(`watching ${type}...`)
ref.on('value', handler) ref.on('value', handler)
return () => { return () => {
console.log(`stop watching ${type}`)
ref.off('value', handler) ref.off('value', handler)
} }
} }
import Vue from 'vue' import Vue from 'vue'
import Vuex from 'vuex' import Vuex from 'vuex'
import { fetchIdsByType, fetchItems } from './api' import { fetchIdsByType, fetchItem, fetchItems } from './api'
Vue.use(Vuex) Vue.use(Vuex)
...@@ -23,17 +23,23 @@ const store = new Vuex.Store({ ...@@ -23,17 +23,23 @@ const store = new Vuex.Store({
actions: { actions: {
// ensure data for rendering given list type // ensure data for rendering given list type
FETCH_DATA_FOR_TYPE: ({ commit, dispatch, state, getters }, { type }) => { FETCH_LIST_DATA: ({ commit, dispatch, state, getters }, { type }) => {
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(() => dispatch('FETCH_ACTIVE_ITEMS')) .then(() => dispatch('ENSURE_ACTIVE_ITEMS'))
}, },
// ensure all active items are fetched // ensure all active items are fetched
FETCH_ACTIVE_ITEMS: ({ commit, state, getters }) => { ENSURE_ACTIVE_ITEMS: ({ dispatch, getters }) => {
return dispatch('FETCH_ITEMS', {
ids: getters.activeIds
})
},
FETCH_ITEMS: ({ commit, state }, { ids }) => {
// only fetch items that we don't already have. // only fetch items that we don't already have.
const ids = getters.activeIds.filter(id => !state.items[id]) ids = ids.filter(id => !state.items[id])
if (ids.length) { if (ids.length) {
return fetchItems(ids).then(items => commit('SET_ITEMS', { items })) return fetchItems(ids).then(items => commit('SET_ITEMS', { items }))
} else { } else {
......
...@@ -7,6 +7,6 @@ ...@@ -7,6 +7,6 @@
<script> <script>
export default { export default {
name: 'about' name: 'about-view'
} }
</script> </script>
import NewsList from '../components/NewsList.vue' import ItemList from '../components/ItemList.vue'
// 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.
export function createListView (type) { export function createListView (type) {
return { return {
name: `${type}-stories`, name: `${type}-stories-view`,
components: {
NewsList
},
// this will be called during SSR to pre-fetch data into the store! // this will be called during SSR to pre-fetch data into the store!
preFetch (store) { preFetch (store) {
return store.dispatch('FETCH_DATA_FOR_TYPE', { type }) return store.dispatch('FETCH_LIST_DATA', { type })
},
created () {
this.$store.commit('SET_ACTIVE_TYPE', { type })
}, },
render (h) { render (h) {
return h(NewsList, { props: { type }}) return h(ItemList, { props: { type }})
} }
} }
} }
<template>
<div class="item-view">
<h2>Item!</h2>
<p v-if="item">{{ item.title }}</p>
</div>
</template>
<script>
export default {
name: 'item-view',
computed: {
item () {
return this.$store.state.items[this.$route.params.id]
}
},
beforeMount () {
this.$store.dispatch('FETCH_ITEMS', {
ids: [this.$route.params.id]
})
}
}
</script>
<template>
<div class="user-view">
<h2>User!</h2>
</div>
</template>
<script>
export default {
name: 'user-view',
preFetch (store) {
return store.dispatch('FETCH_USER', {
id: store.state.route.params.id
})
},
mounted () {
}
}
</script>
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