Allow only values that can be serialized to key (#6881)

@ijjk
This commit is contained in:
Tim Neutkens 2019-04-03 20:43:20 +02:00 committed by GitHub
parent 84ca9a7b10
commit b38446717a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -2,28 +2,44 @@ import {useContext} from 'react'
import { DataManagerContext } from 'next-server/dist/lib/data-manager-context' import { DataManagerContext } from 'next-server/dist/lib/data-manager-context'
import { RouterContext } from 'next-server/dist/lib/router-context' import { RouterContext } from 'next-server/dist/lib/router-context'
import fetch from 'unfetch' import fetch from 'unfetch'
import {stringify} from 'querystring'
export function createHook(fetcher: (...args: any) => Promise<any>, options: {key: string}) { type Args = string|number|Array<string|number>
function generateArgsKey(args: Args[]) {
return args.reduce((a: string, b: Args): string => {
if (Array.isArray(b)) {
return a + generateArgsKey(b)
}
if (typeof b !== 'string' && typeof b !== 'number') {
throw new Error('arguments can only be string or number')
}
return a + b.toString()
}, '')
}
export function createHook(fetcher: (...args: Args[]) => Promise<any>, options: {key: string}) {
if (!options.key) { if (!options.key) {
throw new Error('key not provided to createHook options.') throw new Error('key not provided to createHook options.')
} }
return function useData(...args: any) { return function useData(...args: Array<string|number>) {
const router: import('next-server/lib/router/router').default = useContext(RouterContext) const router: import('next-server/lib/router/router').default = useContext(RouterContext)
const dataManager: import('next-server/lib/data-manager').DataManager = useContext(DataManagerContext) const dataManager: import('next-server/lib/data-manager').DataManager = useContext(DataManagerContext)
const existing = dataManager.get(options.key) const key = `${router.route}${options.key}${generateArgsKey(args)}`
const existing = dataManager.get(key)
if (existing && existing.status === 'resolved') { if (existing && existing.status === 'resolved') {
return existing.result return existing.result
} }
// @ts-ignore webpack optimization // @ts-ignore webpack optimization
if (process.browser) { if (process.browser) {
const res = fetch(router.route === '/' ? 'index.json' : router.route + '.json').then((res: any) => res.json()).then((result: any) => { const res = fetch(router.route === '/' ? 'index.json' : router.route + '.json?' + stringify(router.query)).then((res: any) => res.json()).then((result: any) => {
dataManager.overwrite(result) dataManager.overwrite(result)
}) })
throw res throw res
} else { } else {
const res = fetcher(...args).then((result) => { const res = fetcher(...args).then((result) => {
dataManager.set(options.key, { dataManager.set(key, {
status: 'resolved', status: 'resolved',
result, result,
}) })