Load data async

How can I trigger some data load asynchronously (with AbortController for cancelling) and show if not loaded some Loading-Component? I think I did something wrong with lazy...
import { For, JSX, lazy, Show, Suspense } from "solid-js";
import type { DataTableCell } from "./DataTableCell";
import { DataTableColumnHeader } from "./DataTableColumnHeader";

type NonEmptyArray<T> = [T, ...T[]];

export interface DataTableColumn {
title: JSX.Element | string;
}

export interface DataTableCellProps<T> {
value: T;
readonly: boolean;
onValidate?: (value: T) => boolean;
onChange?: (value: T) => void;
}

export type DataTableCell = (props: DataTableCellProps<any>) => JSX.Element;

export const DataTableTextCell = (props: DataTableCellProps<string>) => {
return <td class="data-table-cell data-table-cell-text">
<span class="data-table-cell--content" contentEditable={!props.readonly}>{props.value}</span>
</td>
}

export interface DataTableProps {
columns: NonEmptyArray<DataTableColumn>;
dataProvider?: DataProvider | undefined;
filters?: DataFilter[];
}

export interface DataFilter { }

export interface DataProvider {
getData(filters: DataFilter[], signal: AbortSignal): Promise<DataTableCell[]>;
}

export const DataTable = (props: DataTableProps) => {
let controller = new AbortController();
let dataPromise = props.dataProvider?.getData(props.filters ?? [], controller.signal);
let data = lazy(async () => {
let data = await dataPromise;
return <For each={data}>{(item) => <div></div>}</For>
});

return <table>
<tr>
{props.columns.map((column) => <DataTableColumnHeader title={column.title} />)}
</tr>
<Show when={props.dataProvider} fallback={<b>No data provider</b>}>
<Suspense fallback={<div>Loading</div>}>

</Suspense>
</Show>
</table>
};
import { For, JSX, lazy, Show, Suspense } from "solid-js";
import type { DataTableCell } from "./DataTableCell";
import { DataTableColumnHeader } from "./DataTableColumnHeader";

type NonEmptyArray<T> = [T, ...T[]];

export interface DataTableColumn {
title: JSX.Element | string;
}

export interface DataTableCellProps<T> {
value: T;
readonly: boolean;
onValidate?: (value: T) => boolean;
onChange?: (value: T) => void;
}

export type DataTableCell = (props: DataTableCellProps<any>) => JSX.Element;

export const DataTableTextCell = (props: DataTableCellProps<string>) => {
return <td class="data-table-cell data-table-cell-text">
<span class="data-table-cell--content" contentEditable={!props.readonly}>{props.value}</span>
</td>
}

export interface DataTableProps {
columns: NonEmptyArray<DataTableColumn>;
dataProvider?: DataProvider | undefined;
filters?: DataFilter[];
}

export interface DataFilter { }

export interface DataProvider {
getData(filters: DataFilter[], signal: AbortSignal): Promise<DataTableCell[]>;
}

export const DataTable = (props: DataTableProps) => {
let controller = new AbortController();
let dataPromise = props.dataProvider?.getData(props.filters ?? [], controller.signal);
let data = lazy(async () => {
let data = await dataPromise;
return <For each={data}>{(item) => <div></div>}</For>
});

return <table>
<tr>
{props.columns.map((column) => <DataTableColumnHeader title={column.title} />)}
</tr>
<Show when={props.dataProvider} fallback={<b>No data provider</b>}>
<Suspense fallback={<div>Loading</div>}>

</Suspense>
</Show>
</table>
};
3 Replies
Alex Lohr
Alex Lohr2y ago
There's @solid-primitives/fetch to make abortable requests (using withAbort() modifier). Otherwise you need to manually wrap a call of createResource and be sure to capture the AbortErrors.
Robin Lindner
Robin LindnerOP2y ago
I try it with createResource, but why is the state of the resource == "unresolved"?
export const DataTable = (props: DataTableProps) => {
let [controller, setController]: Signal<AbortController | undefined> = createSignal();

let [data, { mutate, refetch }] = createResource(async () => {
let controller = setController(new AbortController());
let data = await props.dataProvider?.getData(props.filters ?? [], controller.signal);
return <For each={data}>{(item) => item}</For>
});

return <table>
<tr>
<For each={props.columns}>
{(item) => <DataTableColumnHeader title={item.title} />}
</For>
</tr>

<Show when={props.dataProvider} fallback={<tr><b>No data provider</b></tr>}>
<Switch>
<Match when={data.state == "ready"}>
{data()}
</Match>
<Match when={data.state == "pending" || data.state == "refreshing"}>
<tr><button type="button" onClick={() => controller()?.abort()}>Abbrechen</button></tr>
</Match>
<Match when={data.state == "errored"}>
<tr><td>Error</td><td>{data.error}</td></tr>
</Match>
<Match when={data.state == "unresolved"}>
Weird
</Match>
</Switch>
</Show>
</table>
};
export const DataTable = (props: DataTableProps) => {
let [controller, setController]: Signal<AbortController | undefined> = createSignal();

let [data, { mutate, refetch }] = createResource(async () => {
let controller = setController(new AbortController());
let data = await props.dataProvider?.getData(props.filters ?? [], controller.signal);
return <For each={data}>{(item) => item}</For>
});

return <table>
<tr>
<For each={props.columns}>
{(item) => <DataTableColumnHeader title={item.title} />}
</For>
</tr>

<Show when={props.dataProvider} fallback={<tr><b>No data provider</b></tr>}>
<Switch>
<Match when={data.state == "ready"}>
{data()}
</Match>
<Match when={data.state == "pending" || data.state == "refreshing"}>
<tr><button type="button" onClick={() => controller()?.abort()}>Abbrechen</button></tr>
</Match>
<Match when={data.state == "errored"}>
<tr><td>Error</td><td>{data.error}</td></tr>
</Match>
<Match when={data.state == "unresolved"}>
Weird
</Match>
</Switch>
</Show>
</table>
};
ryansolid
ryansolid2y ago
It's going to start as unresolved. It should resolve when the Promise does
Want results from more Discord servers?
Add your server