Skip to content

Commit 48f78b4

Browse files
committed
feat(#7): add an argument postProcess for injectSSRHtml
able to customize ssrHtml and apiCacheScript
1 parent 78e907a commit 48f78b4

File tree

7 files changed

+57
-17
lines changed

7 files changed

+57
-17
lines changed

.prettierrc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"semi": false,
3+
"singleQuote": true
4+
}

README.md

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -195,12 +195,12 @@ const [data, state] = useApi({
195195

196196
### Options [Optional]
197197

198-
| Name | Type | default | Description |
199-
| ------------- | --------------------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
200-
| handleData | Function(data: any, state: ReactUseApi.State) | | A callback function to deal with the data of the API's response. **IMPORTANT** Using any state setter in handleData is dangerous, which will cause the component re-rendering infinitely while SSR rendering. |
201-
| dependencies | Object | | The additional needed data using in handleData. `NOTE`: "dependencies" is supposed to immutable due to React's rendering policy. |
202-
| shouldRequest | Function | | A callback to decide whether useApi re-fetches the API when re-rendering. Returning true will trigger useApi to re-fetch. This option is helpful if you want to re-request an API when a route change occurs. |
203-
| watch | any[] | [] | An array of values that the effect depends on, this is the same as the second argument of useEffect. |
198+
| Name | Type | default | Description |
199+
| ------------- | --------------------------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
200+
| handleData | Function(data: any, state: ReactUseApi.State) | | A callback function to deal with the data of the API's response. **IMPORTANT** Using any state setter in handleData is dangerous, which will cause the component re-rendering infinitely while SSR rendering. |
201+
| dependencies | Object | | The additional needed data using in handleData. `NOTE`: "dependencies" is supposed to immutable due to React's rendering policy. |
202+
| shouldRequest | Function | | A callback to decide whether useApi re-fetches the API when `only re-rendering`. Returning true will trigger useApi to re-fetch. This option is helpful if you want to re-request an API when a route change occurs. |
203+
| watch | any[] | [] | An array of values that the effect depends on, this is the same as the second argument of useEffect. |
204204

205205
## State
206206

@@ -316,7 +316,8 @@ _Each property is optional_
316316
```ts
317317
injectSSRHtml(
318318
context: ReactUseApi.CustomContext,
319-
renderSSR?: () => string
319+
renderSSR?: () => string,
320+
postProcess?: (ssrHtml: string, apiCacheScript: string) => string,
320321
): string
321322

322323
```

src/__tests__/ssr.test.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,34 @@ describe('injectSSRHtml tests', () => {
269269
expect(ssrHtml).toEqual(html)
270270
})
271271

272+
it('should injectSSRHtml work well with postProcess', async () => {
273+
const renderSSR = jest.fn().mockReturnValue(html)
274+
const context = configure({
275+
settings: {
276+
...copySettings()
277+
}
278+
})
279+
const { settings } = context
280+
const { cache } = settings
281+
cache.reset = jest.fn()
282+
cache.set(JSON.stringify({ url: 'foo' }), 'bar')
283+
expect.hasAssertions()
284+
let originSSRHtml = ''
285+
const postProcess = jest.fn((ssrHtml: string, apiCacheScript: string) => {
286+
originSSRHtml = ssrHtml + apiCacheScript
287+
return '404'
288+
})
289+
const ssrHtml = await injectSSRHtml(context, renderSSR, postProcess)
290+
expect(renderSSR).toHaveBeenCalled()
291+
expect(cache.reset).toHaveBeenCalled()
292+
expect(postProcess).toHaveBeenCalled()
293+
expect(feedRequests).toHaveBeenLastCalledWith(context, html)
294+
expect(originSSRHtml).toEqual(
295+
`${html}<script>window.__USE_API_CACHE__ = ${apiTestCacheJson}</script>`
296+
)
297+
expect(ssrHtml).toEqual('404')
298+
})
299+
272300
it('should rule the uncached data out by shouldUseApiCache()', async () => {
273301
const renderSSR = jest.fn().mockReturnValue(html)
274302
const context = configure({

src/common.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ export const defaultSettings = {
1212
clientCacheVar: '__USE_API_CACHE__',
1313
isSSR: (...args: any[]): boolean | void => typeof window === 'undefined',
1414
renderSSR: (...args: any[]): string => '',
15+
// skip: (config?: ReactUseApi.Config, cacheKey?: string): boolean | void =>
16+
// false,
1517
shouldUseApiCache: (
1618
config?: ReactUseApi.Config,
1719
cacheKey?: string

src/ssr.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { configure, axiosAll, defaultSettings } from './common'
1+
import { configure, axiosAll, defaultSettings, isFunction } from './common'
22

33
export const feedRequests = async (
44
context: ReactUseApi.Context,
@@ -62,7 +62,8 @@ export const feedRequests = async (
6262

6363
export const injectSSRHtml = async (
6464
context: ReactUseApi.CustomContext,
65-
renderSSR?: ReactUseApi.Settings['renderSSR']
65+
renderSSR?: ReactUseApi.Settings['renderSSR'],
66+
postProcess?: (ssrHtml: string, apiCacheScript: string) => string
6667
) => {
6768
context = configure(context, true)
6869
const { settings } = context
@@ -82,10 +83,15 @@ export const injectSSRHtml = async (
8283
}
8384
return shouldUseApiCache(config, cacheKey) !== false
8485
})
85-
const axiosHooksScript = `<script>window.${clientCacheVar} = ${JSON.stringify(
86-
cacheJson
87-
).replace(/</g, '\\u003c')}</script>`
88-
return ssrHtml + axiosHooksScript
86+
const apiCacheScript = Object.keys(cacheJson)
87+
? `<script>window.${clientCacheVar} = ${JSON.stringify(cacheJson).replace(
88+
/</g,
89+
'\\u003c'
90+
)}</script>`
91+
: ''
92+
return isFunction(postProcess)
93+
? postProcess(ssrHtml, apiCacheScript)
94+
: ssrHtml + apiCacheScript
8995
}
9096
return ssrHtml
9197
}

src/typings.d.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,10 @@ declare namespace ReactUseApi {
3939
}
4040
interface Options {
4141
watch?: any[]
42+
dependencies?: dependencies
4243
handleData?: (data: Data, newState: State) => any
4344
shouldRequest?: () => boolean | void
44-
dependencies?: dependencies
45+
// skip?: (config?: ReactUseApi.Config, cacheKey?: string) => boolean | void
4546
$cacheKey?: string
4647
}
4748
interface dependencies {

src/useApi.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -199,9 +199,7 @@ export const handleUseApiOptions = (
199199
? ({ ...opt } as ReactUseApi.Options)
200200
: ({
201201
watch: Array.isArray(opt) ? opt : [],
202-
handleData: isFunction(opt) ? opt : undefined,
203-
shouldRequest: undefined,
204-
dependencies: undefined
202+
handleData: isFunction(opt) ? opt : undefined
205203
} as ReactUseApi.Options)
206204
options.$cacheKey = cacheKey
207205
return options

0 commit comments

Comments
 (0)