Kaioken useAsync
hook
This commit is contained in:
parent
833e9363d8
commit
349cc16819
2
Makefile
2
Makefile
@ -12,7 +12,7 @@ init:
|
||||
|
||||
.PHONY: dev
|
||||
dev:
|
||||
cd docz; npm run start -- --host=0.0.0.0; cd ..
|
||||
cd docz; npm run start -- --host=0.0.0.0 --no-open; cd ..
|
||||
|
||||
.PHONY: serve
|
||||
serve:
|
||||
|
@ -137,7 +137,7 @@ When the file header is not known in advance, `any` should be used.
|
||||
|
||||
The SheetJS [`read`](/docs/api/parse-options) and [`sheet_to_json`](/docs/api/utilities/array#array-output)
|
||||
functions simplify state updates. They are best used in the function bodies of
|
||||
`useEffect`[^2] and `useCallback`[^3] hooks.
|
||||
`useAsync`[^2], `useEffect`[^3] and `useCallback`[^4] hooks.
|
||||
|
||||
A `useEffect` hook can download and update state when a person loads the site:
|
||||
|
||||
@ -213,6 +213,41 @@ useEffect(() => { (async() => {
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
:::info pass
|
||||
|
||||
For this particular use case (fetching a file once when the page loads), it is
|
||||
strongly recommended to use the `useAsync` hook:
|
||||
|
||||
```ts
|
||||
import { useAsync } from 'kaioken';
|
||||
import { read, utils } from 'xlsx';
|
||||
|
||||
/* Fetch and parse the file */
|
||||
// highlight-next-line
|
||||
const [ pres, loading, error ] = useAsync<President[]>(async() => {
|
||||
/* Download from https://docs.sheetjs.com/pres.numbers */
|
||||
const f = await fetch("https://docs.sheetjs.com/pres.numbers");
|
||||
const ab = await f.arrayBuffer();
|
||||
|
||||
/* parse */
|
||||
const wb = read(ab);
|
||||
|
||||
/* generate array of presidents from the first worksheet */
|
||||
const ws = wb.Sheets[wb.SheetNames[0]]; // get the first worksheet
|
||||
const data: President[] = utils.sheet_to_json<President>(ws); // generate objects
|
||||
|
||||
// highlight-start
|
||||
/* return data -- essentially setting state */
|
||||
return data;
|
||||
// highlight-end
|
||||
}, []);
|
||||
```
|
||||
|
||||
SheetJS users reported that it is easier to reason about data fetching using the
|
||||
`useAsync` pattern compared to the traditional `useEffect` jujutsu.
|
||||
|
||||
:::
|
||||
|
||||
#### Rendering Data
|
||||
|
||||
Kaioponents typically render HTML tables from arrays of objects. The `TR` table
|
||||
@ -243,7 +278,7 @@ in the example JSX code:
|
||||
|
||||
The [`writeFile`](/docs/api/write-options) and [`json_to_sheet`](/docs/api/utilities/array#array-of-objects-input)
|
||||
functions simplify exporting data. They are best used in the function bodies of
|
||||
`useCallback`[^4] hooks attached to button or other elements.
|
||||
`useCallback`[^5] hooks attached to button or other elements.
|
||||
|
||||
A callback can generate a local file when a user clicks a button:
|
||||
|
||||
@ -278,7 +313,84 @@ const exportFile = useCallback(() => {
|
||||
#### Complete Kaioponent
|
||||
|
||||
This complete Kaioponent example fetches a test file and displays the data in a
|
||||
HTML table. When the export button is clicked, a callback will export a file:
|
||||
HTML table. When the export button is clicked, a callback will export a file.
|
||||
|
||||
Examples using `useAsync` and `useEffect` with `useState` are shown below:
|
||||
|
||||
<Tabs groupId="hook">
|
||||
<TabItem name="async" value="useAsync">
|
||||
|
||||
```tsx title="src/SheetJSKaiokenAoO.tsx"
|
||||
import { useAsync, useCallback } from "kaioken";
|
||||
import { read, utils, writeFileXLSX } from 'xlsx';
|
||||
|
||||
interface President {
|
||||
Name: string;
|
||||
Index: number;
|
||||
}
|
||||
|
||||
export default function SheetJSKaiokenAoO() {
|
||||
/* Fetch and parse the file */
|
||||
const [ pres, loading, error ] = useAsync<President[]>(async() => {
|
||||
const f = await (await fetch("https://docs.sheetjs.com/pres.xlsx")).arrayBuffer();
|
||||
const wb = read(f); // parse the array buffer
|
||||
const ws = wb.Sheets[wb.SheetNames[0]]; // get the first worksheet
|
||||
const data = utils.sheet_to_json<President>(ws); // generate objects
|
||||
return data;
|
||||
}, []);
|
||||
|
||||
/* get state data and export to XLSX */
|
||||
const exportFile = useCallback(() => {
|
||||
const ws = utils.json_to_sheet(pres!);
|
||||
const wb = utils.book_new();
|
||||
utils.book_append_sheet(wb, ws, "Data");
|
||||
writeFileXLSX(wb, "SheetJSKaiokenAoO.xlsx");
|
||||
}, [pres]);
|
||||
|
||||
return (<table><thead><tr><th>Name</th><th>Index</th></tr></thead><tbody>
|
||||
{ /* generate row for each president */
|
||||
pres && pres.map(pres => (<tr>
|
||||
<td>{pres.Name}</td>
|
||||
<td>{pres.Index}</td>
|
||||
</tr>))
|
||||
}
|
||||
{ /* loading message */
|
||||
!pres && loading && ( <tr><td colSpan="2">Loading ...</td></tr> )
|
||||
}
|
||||
{ /* error message */
|
||||
!pres && !loading && ( <tr><td colSpan="2">{error.message}</td></tr> )
|
||||
}
|
||||
</tbody><tfoot><td colSpan={2}>
|
||||
<button onclick={exportFile}>Export XLSX</button>
|
||||
</td></tfoot></table>);
|
||||
}
|
||||
```
|
||||
|
||||
:::note pass
|
||||
|
||||
Typically the JSX structure uses ternary expressions for testing status:
|
||||
|
||||
```jsx
|
||||
const [ pres, loading, error ] = useAsync(async() => { /* ... */ });
|
||||
|
||||
return ( <>
|
||||
{ pres ? (
|
||||
<b>Data is loaded</b>
|
||||
) : loading ? (
|
||||
<b>Loading ...</b>
|
||||
) : (
|
||||
<b>{error.message}</b>
|
||||
)
|
||||
}
|
||||
</> );
|
||||
```
|
||||
|
||||
For clarity, the loading and error messages are separated.
|
||||
|
||||
:::
|
||||
|
||||
</TabItem>
|
||||
<TabItem name="effect" value="useEffect + useState">
|
||||
|
||||
```tsx title="src/SheetJSKaiokenAoO.tsx"
|
||||
import { useCallback, useEffect, useState } from "kaioken";
|
||||
@ -323,6 +435,9 @@ export default function SheetJSKaiokenAoO() {
|
||||
}
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
<details open>
|
||||
<summary><b>How to run the example</b> (click to hide)</summary>
|
||||
|
||||
@ -335,7 +450,7 @@ This demo was tested in the following environments:
|
||||
|
||||
| Kaioken | ViteJS | Date |
|
||||
|:---------|:---------|:-----------|
|
||||
| `0.17.0` | `5.2.10` | 2024-04-20 |
|
||||
| `0.17.0` | `5.2.11` | 2024-05-21 |
|
||||
|
||||
:::
|
||||
|
||||
@ -482,7 +597,7 @@ This demo was tested in the following environments:
|
||||
|
||||
| Kaioken | ViteJS | Date |
|
||||
|:---------|:---------|:-----------|
|
||||
| `0.17.0` | `5.2.10` | 2024-04-20 |
|
||||
| `0.17.0` | `5.2.11` | 2024-05-21 |
|
||||
|
||||
:::
|
||||
|
||||
@ -565,7 +680,8 @@ will generate a workbook that can be opened in a spreadsheet editor.
|
||||
|
||||
</details>
|
||||
|
||||
[^1]: See [`useState`](https://kaioken.dev/docs/hooks/usestate) in the Kaioken documentation.
|
||||
[^2]: See [`useEffect`](https://kaioken.dev/docs/hooks/useeffect) in the Kaioken documentation.
|
||||
[^3]: See [`useCallback`](https://kaioken.dev/docs/hooks/usecallback) in the Kaioken documentation.
|
||||
[^4]: See [`useCallback`](https://kaioken.dev/docs/hooks/usecallback) in the Kaioken documentation.
|
||||
[^1]: See [`useState`](https://kaioken.dev/docs/hooks/useState) in the Kaioken documentation.
|
||||
[^2]: See [`useAsync`](https://kaioken.dev/docs/hooks/useAsync) in the Kaioken documentation.
|
||||
[^3]: See [`useEffect`](https://kaioken.dev/docs/hooks/useEffect) in the Kaioken documentation.
|
||||
[^4]: See [`useCallback`](https://kaioken.dev/docs/hooks/useCallback) in the Kaioken documentation.
|
||||
[^5]: See [`useCallback`](https://kaioken.dev/docs/hooks/useCallback) in the Kaioken documentation.
|
||||
|
Loading…
Reference in New Issue
Block a user