caching
This commit is contained in:
parent
473897fdfc
commit
e9cf90180f
1 changed files with 30 additions and 7 deletions
37
src/App.tsx
37
src/App.tsx
|
|
@ -1,5 +1,5 @@
|
|||
import { z } from "zod"
|
||||
import { useReducer, useEffect, createContext, useContext } from "react"
|
||||
import { useReducer, useRef, useEffect, createContext, useContext } from "react"
|
||||
|
||||
// TODO: Use Material UI later.
|
||||
// TODO: Improve error-handling. Introduce some proper server response.
|
||||
|
|
@ -31,13 +31,16 @@ const Dimension = {
|
|||
}
|
||||
|
||||
// === Page ===
|
||||
type PageNumber = number
|
||||
|
||||
type Page = {
|
||||
page: number
|
||||
page: PageNumber
|
||||
limit: number // page size
|
||||
}
|
||||
type PageKey = string
|
||||
|
||||
const LIMIT = 10
|
||||
const FIRST_PAGE = 1
|
||||
const FIRST_PAGE: PageNumber = 1
|
||||
|
||||
const Page = {
|
||||
init(): Page {
|
||||
|
|
@ -55,6 +58,10 @@ const Page = {
|
|||
eq(page0: Page, page1: Page): boolean {
|
||||
return page0.page === page1.page && page0.limit === page1.limit
|
||||
},
|
||||
// for hashing in maps to avoid identity problems
|
||||
key(page: Page): PageKey {
|
||||
return `${page.page}:${page.limit}`
|
||||
},
|
||||
}
|
||||
|
||||
// === api ===
|
||||
|
|
@ -145,13 +152,31 @@ type Msg =
|
|||
function useApp(): [State, Dispatch] {
|
||||
const [state, dispatch] = useReducer(update, State.init())
|
||||
|
||||
// === Caching API calls ===
|
||||
// Could also cache `Promise<ImageId[]>` in case two requests are made really fast one after another (not really the case in this app so whatever)
|
||||
const cacheRef = useRef<Map<PageKey, ImageId[]>>(new Map())
|
||||
|
||||
async function getImageIdsCached(page: Page): Promise<ImageId[]> {
|
||||
const pageKey = Page.key(page)
|
||||
const maybeImages = cacheRef.current.get(pageKey)
|
||||
if (maybeImages === undefined) {
|
||||
console.log("CACHE-MISS")
|
||||
const images = await getImageIds(page)
|
||||
cacheRef.current.set(pageKey, images)
|
||||
return images
|
||||
} else {
|
||||
console.log("CACHE-HIT")
|
||||
return maybeImages
|
||||
}
|
||||
}
|
||||
|
||||
// === initialization & reloading ===
|
||||
useEffect(() => {
|
||||
// TODO: error-handling
|
||||
getImageIds(state.page).then((imageIds) => {
|
||||
getImageIdsCached(state.page).then((imageIds) => {
|
||||
dispatch({ tag: "imagesReceived", forPage: state.page, imageIds })
|
||||
})
|
||||
}, [state.page])
|
||||
}, [state.page]) // Would have been amazing if we could put `Page.key(state.page)` inside of this. Then the trouble with identity would be gone. But we can't, because React compiler and linter would complain /facepalm
|
||||
|
||||
function update(state: State, msg: Msg): State {
|
||||
switch (msg.tag) {
|
||||
|
|
@ -162,7 +187,6 @@ function useApp(): [State, Dispatch] {
|
|||
return state
|
||||
}
|
||||
case "previousButtonClicked": {
|
||||
console.log("prev")
|
||||
const newPage = Page.previous(state.page)
|
||||
if (Page.eq(newPage, state.page)) {
|
||||
return state // preserves identity
|
||||
|
|
@ -171,7 +195,6 @@ function useApp(): [State, Dispatch] {
|
|||
}
|
||||
}
|
||||
case "nextButtonClicked": {
|
||||
console.log("next")
|
||||
return { ...state, page: Page.next(state.page), imageIds: Remote.loading() }
|
||||
}
|
||||
case "imageClicked": {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue