rvx
Version:
A signal based rendering library
169 lines (133 loc) • 3.63 kB
Markdown
The `<Async>` component is meant for asynchronous rendering. E.g. loading page content.
=== "JSX"
```jsx
import { Async } from "rvx/async";
// main.tsx:
<Async source={() => import("./page")}>
{page => <page.content />}
</Async>
// page.tsx:
export function content() {
return <h1>Hello World!</h1>;
}
```
=== "No Build"
```jsx
import { nestAsync } from "./rvx.async.js";
// main.js:
nestAsync(() => import("./page"), page => page.content())
// page.js:
export function content() {
return e("h1").append("Hello World!");
}
```
The `rejected` and `pending` properties can be used for rendering content when the promise is rejected or pending:
=== "JSX"
```jsx
<Async
source={() => import("./page")}
pending={() => <>Loading...</>}
rejected={error => <>Error: {error}</>}
>
{page => <page.content />}
</Async>
```
=== "No Build"
```jsx
nestAsync(
() => import("./page"),
page => page.content(),
() => "Loading...",
error => ["Error: ", error],
)
```
To wait for async parts in a specific context to complete, you can use `AsyncContexts`:
=== "JSX"
```jsx
import { Inject } from "rvx";
import { ASYNC, Async, AsyncContext } from "rvx/async";
const ctx = new AsyncContext();
<Inject context={ASYNC} value={ctx}>
{() => <Async>...</Async>}
</Inject>
// Wait for all "<Async>" parts to complete and re-throw unhandled errors:
await ctx.complete();
// Or manually track an async task:
ctx.track(fetch("something"));
```
=== "No Build"
```jsx
import { ASYNC, Async, AsyncContext } from "./rvx.async.js";
const ctx = new AsyncContext();
ASYNC.inject(ctx, () => {
return nestAsync(...);
})
// Wait for all "<Async>" parts to complete and re-throw unhandled errors:
await ctx.complete();
// Or manually track an async task:
ctx.track(fetch("something"));
```
When there are multiple async parts in the same place, tracking can be used to hide an entire area and show it once all of the inner async parts have completed.
=== "JSX"
```jsx
import { $, Inject, movable } from "rvx";
import { ASYNC, Async, AsyncContext } from "rvx/async";
const innerCtx = new AsyncContext();
const inner = movable(
<Inject context={ASYNC} value={innerCtx}>
{() => <>
<Async>...</Async>
<Async>...</Async>
<Async>...</Async>
</>}
</Inject>
);
<Async source={innerCtx.complete()}>
{() => inner.move()}
</Async>
```
=== "No Build"
```jsx
import { $, movable } from "./rvx.js";
import { ASYNC, nestAsync, AsyncContext } from "./rvx.async.js";
const innerCtx = new AsyncContext();
const inner = movable(ASYNC.inject(innerCtx, () => [
nestAsync(...),
nestAsync(...),
nestAsync(...),
]));
nestAsync(innerCtx.complete(), () => inner.move())
```
The `<Show>` or `<Nest>` components can be used to replace the `source` property over time:
=== "JSX"
```jsx
<Show when={someSignal}>
{source => <Async source={source}>...</Async>}
</Show>
```
=== "No Build"
```jsx
when(someSignal, source => nestAsync(source, ...))
```
The example below fetches a file and aborts pending requests when the file name is changed early:
=== "JSX"
```jsx
const name = $("example.txt");
<Nest watch={name}>
{name => <Async source={fetch(name, { signal: useAbortSignal() }).then(r => r.text())}>
{text => <pre>{text}</pre>}
</Async>}
</Nest>
```
=== "No Build"
```jsx
const name = $("example.txt");
nest(name, name => nestAsync(
fetch(name, { signal: useAbortSignal() }).then(r => r.text()),
text => e("pre").append(text)
))
```