Skip to content

Commit

Permalink
🎁 Improve data fetching & store words locally (#65)
Browse files Browse the repository at this point in the history
* Use generator function to recursively fetch words
* Check for localforage data before fetching
  • Loading branch information
stormwarning authored Sep 5, 2019
1 parent 46a1674 commit 2b29ec8
Show file tree
Hide file tree
Showing 5 changed files with 141 additions and 29 deletions.
21 changes: 21 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"dependencies": {
"@nuxtjs/google-analytics": "2.2.x",
"@nuxtjs/pwa": "3.0.0-beta.16",
"localforage": "1.7.3",
"nuxt": "2.9.x",
"vue-mq": "1.0.1"
},
Expand Down
4 changes: 2 additions & 2 deletions pages/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,11 @@ export default {
},
mounted() {
this.fetchWords()
this.getWords()
},
methods: {
...mapActions(['fetchWords']),
...mapActions(['getWords']),
},
}
</script>
Expand Down
47 changes: 20 additions & 27 deletions store/index.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,4 @@
let wordlist = []
let skip = 0

function getAllWords(endpoint, callback) {
const getWords = fetch(endpoint)

getWords
.then((data) => data.json())
.then((data) => {
for (const i in data.items) {
wordlist.push(data.items[i])
}

// Pages are always 100 items or less.
if (data.items.length < 100) {
callback(wordlist)
} else {
skip = skip + 100
getAllWords(endpoint + '&skip=' + skip, callback)
}
})
}
import { fetchWords, retrieveWords, storeWords } from '../utils/api'

export const state = () => ({
version: process.env.VERSION,
Expand Down Expand Up @@ -68,11 +47,8 @@ export const mutations = {
}

export const actions = {
fetchWords({ state, commit }) {
let dataURL =
'https://cdn.contentful.com/spaces/8j8wvx07a2uv/entries?access_token=f582803bba0fe0513deecb0f9edf8e0e0d31c631247ccc64d7d99087e7a75e85'

getAllWords(dataURL, (wordlist) => {
getWords({ state, commit }) {
function commitWordsToState(wordlist) {
commit('setWordList', wordlist)
commit('setWordsLoaded', true)

Expand All @@ -86,6 +62,23 @@ export const actions = {
let adjective = filteredWords[w].fields.word

commit('setAdjective', adjective)
}

retrieveWords().then((words) => {
if (words) {
commitWordsToState(words)
} else {
/**
* If there's no words in localstorage, fetch 'em from
* the API, commit to state, and store locally.
*/
fetchWords({
onComplete: (words) => {
commitWordsToState(words)
storeWords(words)
},
})
}
})
},
}
97 changes: 97 additions & 0 deletions utils/api.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import localforage from 'localforage'

const ENDPOINT = 'https://cdn.contentful.com/spaces/8j8wvx07a2uv/entries'
const TOKEN = 'f582803bba0fe0513deecb0f9edf8e0e0d31c631247ccc64d7d99087e7a75e85'

localforage.config({
name: 'Gibson Ipsum',
storeName: 'gibsonipsum',
description: 'Store array of words for offline use.',
})

function* fetchAllWords({ url, nextSkip }) {
let shouldFetch = true

// Loop forever, yielding the results of the ajax call.
while (true) {
yield fetch(url)
.then((resp) => resp.json())
.then((resp) => {
let { items, skip, total } = resp

if (items && items.length > 0) {
/**
* Set the endpoint URL and boolean flag for the
* next time this generator runs.
*/
nextSkip = skip + 100
url = `${ENDPOINT}?access_token=${TOKEN}&skip=${nextSkip}`
shouldFetch = skip + items.length < total

return { words: items, shouldFetch }
} else {
return null
}
})
}
}

export async function fetchWords(opts) {
/**
* Initialize the array where we store the words (only called the
* first time through this function).
*/
if (!opts.hasOwnProperty('wordlist')) {
opts.wordlist = []
}

/**
* Make the initial call to get the generator, specifying the url
* to get the first page of data.
*/
if (!opts.hasOwnProperty('fetch')) {
opts.fetch = await fetchAllWords({
url: `${ENDPOINT}?access_token=${TOKEN}`,
nextSkip: 0,
})
}

let { fetch, wordlist, onComplete } = opts
let next = fetch.next()

/**
* Get the result of the most recent ajax call from the
* generator function.
*/
next.value.then(({ words, shouldFetch }) => {
/**
* Append words to main list and either call this function
* again, or the callback function.
*/
if (words) {
wordlist = wordlist.concat(words)
shouldFetch
? fetchWords({ fetch, wordlist, onComplete })
: onComplete(wordlist)
} else {
onComplete(wordlist)
}
})
}

export const retrieveWords = () => {
return localforage.getItem('words').then((res) => {
return res
})
}

export const storeWords = (wordsArray) => {
return localforage
.setItem('words', wordsArray)
.then((value) => {
return value
})
.catch((err) => {
console.log('There was an error storing the words.', err)
})
}

1 comment on commit 2b29ec8

@vercel
Copy link

@vercel vercel bot commented on 2b29ec8 Sep 5, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.