Commit 5b70c6d2 authored by Evan You's avatar Evan You

fetch real data

parent 384d74e3
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
"dependencies": { "dependencies": {
"es6-promise": "^3.2.1", "es6-promise": "^3.2.1",
"express": "^4.14.0", "express": "^4.14.0",
"firebase": "^2.4.2",
"lru-cache": "^4.0.1", "lru-cache": "^4.0.1",
"serialize-javascript": "^1.3.0", "serialize-javascript": "^1.3.0",
"serve-favicon": "^2.3.0", "serve-favicon": "^2.3.0",
......
<template> <template>
<div id="app"> <div id="app">
<img src="./assets/logo.png">
<h1>{{ msg }}</h1>
<p>Store state:</p>
<pre>{{ JSON.stringify($store.state, null, 2) }}</pre>
<ul> <ul>
<li><router-link to="/">News</router-link></li> <li><router-link to="/">News</router-link></li>
<li><router-link to="/about">About</router-link></li> <li><router-link to="/about">About</router-link></li>
...@@ -14,16 +10,6 @@ ...@@ -14,16 +10,6 @@
</div> </div>
</template> </template>
<script>
export default {
data () {
return {
msg: 'Hello Vue 2.0!'
}
}
}
</script>
<style> <style>
body { body {
font-family: Helvetica, sans-serif; font-family: Helvetica, sans-serif;
......
...@@ -4,14 +4,13 @@ export default context => { ...@@ -4,14 +4,13 @@ export default context => {
// set router's initial location // set router's initial location
router.setInitialLocation(context.url) router.setInitialLocation(context.url)
// resolve store state // resolve store state
return Promise.all(router.history.current.matched.map(m => { var s = Date.now()
return Promise.all(Object.keys(m.components).map(key => { return Promise.all(router.getMatchedComponents().map(component => {
const component = m.components[key]
if (component.prefetch) { if (component.prefetch) {
return component.prefetch(store) return component.prefetch(store)
} }
}))
})).then(() => { })).then(() => {
console.log('data fetch: ' + (Date.now() - s))
context.initialState = store.state context.initialState = store.state
return app return app
}) })
......
export function fetchItems (ids) { import Firebase from 'firebase'
return new Promise(resolve => {
resolve([{ id: 1, title: 'foo' }, { id: 2, title: 'bar' }]) const api = new Firebase('https://hacker-news.firebaseio.com/v0')
function fetch (child) {
return new Promise((resolve, reject) => {
api.child(child).once('value', snapshot => {
resolve(snapshot.val())
}, reject)
})
}
export function fetchTopIds () {
return fetch(`topstories`)
}
export function watchTopIds (cb) {
api.child(`topstories`).on('value', snapshot => {
cb(snapshot.val())
}) })
} }
export function fetchItem (id) {
return fetch(`item/${id}`)
}
export function fetchItems (ids) {
return Promise.all(ids.map(id => fetchItem(id)))
}
import Vue from 'vue' import Vue from 'vue'
import Vuex from 'vuex' import Vuex from 'vuex'
import { fetchItems } from './api' import { watchTopIds, fetchTopIds, fetchItems } from './api'
Vue.use(Vuex) Vue.use(Vuex)
// pre-fetched state injected by SSR const inBrowser = typeof window !== 'undefined'
const serverState = typeof window !== 'undefined' && window.__INITIAL_STATE__
// default state // if in browser, use pre-fetched state injected by SSR
const defaultState = { const state = (inBrowser && window.__INITIAL_STATE__) || {
storiesPerPage: 30, storiesPerPage: 30,
topStoryIds: [], topStoryIds: [],
items: {} items: {}
} }
export default new Vuex.Store({ const store = new Vuex.Store({
state: serverState || defaultState, state,
mutations: {
RECEIVE_ITEMS: (state, { items }) => {
for (const id in items) {
Vue.set(state.items, id, items[id])
}
}
},
actions: { actions: {
FETCH_NEWS_BY_PAGE: ({ commit, state }, { page }) => { FETCH_TOP_IDS: ({ commit }) => {
const { storiesPerPage, topStoryIds } = state return fetchTopIds().then(ids => {
const start = (page - 1) * storiesPerPage commit('RECEIVE_TOP_IDS', { ids })
const end = page * storiesPerPage })
const ids = topStoryIds.slice(start, end) },
FETCH_NEWS: ({ commit, state }) => {
const ids = getDisplayedIds(state).filter(id => !state.items.id)
return fetchItems(ids).then(items => { return fetchItems(ids).then(items => {
commit('RECEIVE_ITEMS', { items }) commit('RECEIVE_ITEMS', { items })
}) })
} }
},
mutations: {
RECEIVE_TOP_IDS: (state, { ids }) => {
state.topStoryIds = ids
},
RECEIVE_ITEMS: (state, { items }) => {
items.forEach(item => {
Vue.set(state.items, item.id, item)
})
}
},
getters: {
news: state => {
const ids = getDisplayedIds(state)
return ids.map(id => state.items[id]).filter(_ => _)
}
} }
}) })
if (inBrowser) {
watchTopIds(ids => {
store.commit('RECEIVE_TOP_IDS', { ids })
})
}
function getDisplayedIds (state) {
const page = state.route.params.page || 1
const { storiesPerPage, topStoryIds } = state
const start = (page - 1) * storiesPerPage
const end = page * storiesPerPage
return topStoryIds.slice(start, end)
}
export default store
<template> <template>
<div> <div>
<h2>News</h2> <h2>News</h2>
<p>hihihi</p> <ul>
<li v-for="item in news" :key="item.id">
{{ item.title }}
</li>
</ul>
</div> </div>
</template> </template>
<script> <script>
const fetchData = store => {
return store
.dispatch(`FETCH_TOP_IDS`)
.then(() => store.dispatch(`FETCH_NEWS`))
}
export default { export default {
name: 'news', name: 'news',
prefetch (store) { prefetch: fetchData,
const page = store.state.route.params.page mounted () {
return store.dispatch('FETCH_NEWS_BY_PAGE', page) fetchData(this.$store)
},
computed: {
news () {
return this.$store.getters.news
}
} }
} }
</script> </script>
...@@ -9,6 +9,9 @@ module.exports = merge(webpackConfig, { ...@@ -9,6 +9,9 @@ module.exports = merge(webpackConfig, {
filename: 'server-bundle.js', filename: 'server-bundle.js',
libraryTarget: 'commonjs2' libraryTarget: 'commonjs2'
}, },
externals: {
firebase: true
},
plugins: [ plugins: [
new webpack.DefinePlugin({ new webpack.DefinePlugin({
'process.env': { 'process.env': {
......
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