fixing table list loading link params
This commit is contained in:
parent
732aca1abf
commit
59c8ddc716
|
|
@ -36,6 +36,7 @@ import { MDLocal } from "../md/utils/typings";
|
||||||
import { Skeleton } from "../ui/skeleton";
|
import { Skeleton } from "../ui/skeleton";
|
||||||
import { toast } from "../ui/toast";
|
import { toast } from "../ui/toast";
|
||||||
import { sortTree } from "./utils/sort-tree";
|
import { sortTree } from "./utils/sort-tree";
|
||||||
|
import { getPathname } from "lib/exports";
|
||||||
|
|
||||||
type OnRowClick = (arg: {
|
type OnRowClick = (arg: {
|
||||||
row: any;
|
row: any;
|
||||||
|
|
@ -129,235 +130,262 @@ export const TableList: FC<TableListProp> = ({
|
||||||
if (ls_sort) {
|
if (ls_sort) {
|
||||||
ls_sort = JSON.parse(ls_sort as any);
|
ls_sort = JSON.parse(ls_sort as any);
|
||||||
}
|
}
|
||||||
const local = useLocal({
|
const local = useLocal(
|
||||||
selectedRows: [] as {
|
{
|
||||||
pk: string | number;
|
times: 0,
|
||||||
rows: any;
|
selectedRows: [] as {
|
||||||
}[],
|
pk: string | number;
|
||||||
el: null as null | HTMLDivElement,
|
rows: any;
|
||||||
width: 0,
|
}[],
|
||||||
height: 0,
|
el: null as null | HTMLDivElement,
|
||||||
selectedRowIds: [] as (string | number)[],
|
width: 0,
|
||||||
rob: new ResizeObserver(([e]) => {
|
height: 0,
|
||||||
local.height = e.contentRect.height;
|
selectedRowIds: [] as (string | number)[],
|
||||||
local.width = e.contentRect.width;
|
rob: new ResizeObserver(([e]) => {
|
||||||
if (local.status === "ready") local.status = "resizing";
|
local.height = e.contentRect.height;
|
||||||
local.render();
|
local.width = e.contentRect.width;
|
||||||
}),
|
if (local.status === "ready") local.status = "resizing";
|
||||||
pk: null as null | GFCol,
|
local.render();
|
||||||
scrolled: false,
|
}),
|
||||||
data: [] as any[],
|
pk: null as null | GFCol,
|
||||||
status: "init" as
|
scrolled: false,
|
||||||
| "loading"
|
data: [] as any[],
|
||||||
| "ready"
|
status: "init" as
|
||||||
| "resizing"
|
| "loading"
|
||||||
| "reload"
|
| "ready"
|
||||||
| "init"
|
| "resizing"
|
||||||
| "error",
|
| "reload"
|
||||||
where: null as any,
|
| "init"
|
||||||
firstKey: "",
|
| "error",
|
||||||
should_toast: true,
|
where: null as any,
|
||||||
paging: {
|
firstKey: "",
|
||||||
take: 0,
|
should_toast: true,
|
||||||
skip: 0,
|
paging: {
|
||||||
timeout: null as any,
|
take: 0,
|
||||||
total: 0,
|
skip: 0,
|
||||||
scroll: (currentTarget: HTMLDivElement) => {
|
timeout: null as any,
|
||||||
if (local.status === "loading" || !isAtBottom(currentTarget)) return;
|
total: 0,
|
||||||
if (local.data.length >= local.paging.skip + local.paging.take) {
|
scroll: (currentTarget: HTMLDivElement) => {
|
||||||
local.paging.skip += local.paging.take;
|
if (local.status === "loading" || !isAtBottom(currentTarget)) return;
|
||||||
local.status = "reload";
|
if (local.data.length >= local.paging.skip + local.paging.take) {
|
||||||
local.render();
|
local.paging.skip += local.paging.take;
|
||||||
}
|
local.status = "reload";
|
||||||
},
|
local.render();
|
||||||
},
|
|
||||||
grid_ref: null as null | HTMLDivElement,
|
|
||||||
collapsed: new Set<number>(),
|
|
||||||
cached_row: new WeakMap<any, ReactElement>(),
|
|
||||||
filtering: "" as ReactNode | string | true,
|
|
||||||
reload: (arg?: { toast: boolean }) => {
|
|
||||||
return new Promise<void>((done) => {
|
|
||||||
let should_toast = true;
|
|
||||||
if (arg?.toast === false) should_toast = false;
|
|
||||||
local.should_toast = should_toast;
|
|
||||||
|
|
||||||
local.filtering = "";
|
|
||||||
if (typeof on_load === "function") {
|
|
||||||
local.status = "loading";
|
|
||||||
local.render();
|
|
||||||
|
|
||||||
const orderBy = local.sort.orderBy || undefined;
|
|
||||||
const where = filterWhere(filter_name, __props);
|
|
||||||
|
|
||||||
if (where?.OR?.length > 0) {
|
|
||||||
const key = Object.keys(where.OR[0])[0];
|
|
||||||
if (key && where.OR[0][key]) {
|
|
||||||
let filtering = where.OR[0][key].contains;
|
|
||||||
if (typeof local.filtering === "string") {
|
|
||||||
filtering = filtering.slice(1, -1);
|
|
||||||
} else {
|
|
||||||
filtering = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (filtering) {
|
|
||||||
local.filtering = (
|
|
||||||
<div className="c-pt-2">
|
|
||||||
Searching for: <pre>"{filtering.trim()}"</pre>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
grid_ref: null as null | HTMLDivElement,
|
||||||
|
collapsed: new Set<number>(),
|
||||||
|
cached_row: new WeakMap<any, ReactElement>(),
|
||||||
|
filtering: "" as ReactNode | string | true,
|
||||||
|
reloading: null as any,
|
||||||
|
reload: (arg?: { toast: boolean }) => {
|
||||||
|
if (local.reloading) return local.reloading;
|
||||||
|
|
||||||
if (md) {
|
local.reloading = new Promise<void>(async (done) => {
|
||||||
const last = md.params.links[md.params.links.length - 1];
|
let should_toast = true;
|
||||||
|
if (arg?.toast === false) should_toast = false;
|
||||||
|
local.should_toast = should_toast;
|
||||||
|
|
||||||
if (last && last.where) {
|
local.filtering = "";
|
||||||
if ((last.name && last.name === md.name) || !last.name) {
|
if (typeof on_load === "function") {
|
||||||
for (const [k, v] of Object.entries(last.where)) {
|
local.status = "loading";
|
||||||
where[k] = v;
|
local.render();
|
||||||
|
|
||||||
|
const orderBy = local.sort.orderBy || undefined;
|
||||||
|
const where = filterWhere(filter_name, __props);
|
||||||
|
|
||||||
|
if (where?.OR?.length > 0) {
|
||||||
|
const key = Object.keys(where.OR[0])[0];
|
||||||
|
if (key && where.OR[0][key]) {
|
||||||
|
let filtering = where.OR[0][key].contains;
|
||||||
|
if (typeof local.filtering === "string") {
|
||||||
|
filtering = filtering.slice(1, -1);
|
||||||
|
} else {
|
||||||
|
filtering = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filtering) {
|
||||||
|
local.filtering = (
|
||||||
|
<div className="c-pt-2">
|
||||||
|
Searching for: <pre>"{filtering.trim()}"</pre>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
call_prasi_events("tablelist", "where", [__props?.gen__table, where]);
|
if (md) {
|
||||||
|
if (md.header.loading) {
|
||||||
|
await new Promise<void>((resolve) => {
|
||||||
|
const ival = setInterval(() => {
|
||||||
|
if (!md.header.loading) {
|
||||||
|
clearInterval(ival);
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
}, 10);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const last = md.params.links[md.params.links.length - 1];
|
||||||
|
|
||||||
const load_args: any = {
|
if (last && last.where) {
|
||||||
async reload() {},
|
if ((last.name && last.name === md.name) || !last.name) {
|
||||||
orderBy,
|
for (const [k, v] of Object.entries(last.where)) {
|
||||||
where,
|
where[k] = v;
|
||||||
paging: {
|
}
|
||||||
take: local.paging.take > 0 ? local.paging.take : undefined,
|
}
|
||||||
skip: local.paging.skip,
|
}
|
||||||
},
|
|
||||||
};
|
|
||||||
if (id_parent) {
|
|
||||||
load_args.paging = {};
|
|
||||||
}
|
|
||||||
const result = on_load({ ...load_args, mode: "query" });
|
|
||||||
const callback = (data: any[]) => {
|
|
||||||
if (local.paging.skip === 0) {
|
|
||||||
local.data = data;
|
|
||||||
} else {
|
|
||||||
local.data = [...local.data, ...data];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
local.status = "ready";
|
call_prasi_events("tablelist", "where", [
|
||||||
local.render();
|
__props?.gen__table,
|
||||||
done();
|
where,
|
||||||
|
]);
|
||||||
|
|
||||||
if (local.grid_ref && !id_parent) local.paging.scroll(local.grid_ref);
|
const load_args: any = {
|
||||||
};
|
async reload() {},
|
||||||
|
orderBy,
|
||||||
if (result instanceof Promise) {
|
where,
|
||||||
(async () => {
|
paging: {
|
||||||
try {
|
take: local.paging.take > 0 ? local.paging.take : undefined,
|
||||||
callback(await result);
|
skip: local.paging.skip,
|
||||||
} catch (e) {
|
},
|
||||||
console.error(e);
|
};
|
||||||
local.status = "error";
|
if (id_parent) {
|
||||||
toast.dismiss();
|
load_args.paging = {};
|
||||||
toast.error(
|
}
|
||||||
<div className="c-flex c-text-red-600 c-items-center">
|
const result = on_load({ ...load_args, mode: "query" });
|
||||||
<AlertTriangle className="c-h-4 c-w-4 c-mr-1" />
|
const callback = (data: any[]) => {
|
||||||
Failed to load data
|
if (local.paging.skip === 0) {
|
||||||
</div>,
|
local.data = data;
|
||||||
{
|
} else {
|
||||||
dismissible: true,
|
local.data = [...local.data, ...data];
|
||||||
className: css`
|
|
||||||
background: #ffecec;
|
|
||||||
border: 2px solid red;
|
|
||||||
`,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
})();
|
|
||||||
} else callback(result);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
sort: {
|
|
||||||
columns: (ls_sort?.columns || []) as SortColumn[],
|
|
||||||
on_change: (cols: SortColumn[]) => {
|
|
||||||
if (feature?.find((e) => e === "sorting")) {
|
|
||||||
local.sort.columns = cols;
|
|
||||||
local.paging.skip = 0;
|
|
||||||
if (cols.length > 0) {
|
|
||||||
let { columnKey, direction } = cols[0];
|
|
||||||
|
|
||||||
if (columnKey.includes(".")) {
|
local.status = "ready";
|
||||||
let root: any = {};
|
local.reloading = null;
|
||||||
set(root, columnKey, direction === "ASC" ? "asc" : "desc");
|
local.render();
|
||||||
local.sort.orderBy = root;
|
done();
|
||||||
} else {
|
|
||||||
let should_set = true;
|
|
||||||
const gf = JSON.stringify(gen_fields);
|
|
||||||
const fields = fields_map.get(gf);
|
|
||||||
if (fields) {
|
|
||||||
const rel = fields?.find((e) => e.name === columnKey);
|
|
||||||
if (rel && rel.checked) {
|
|
||||||
should_set = false;
|
|
||||||
|
|
||||||
if (rel.type === "has-many") {
|
if (local.grid_ref && !id_parent)
|
||||||
local.sort.orderBy = {
|
local.paging.scroll(local.grid_ref);
|
||||||
[columnKey]: {
|
};
|
||||||
_count: direction === "ASC" ? "asc" : "desc",
|
|
||||||
},
|
if (result instanceof Promise) {
|
||||||
};
|
(async () => {
|
||||||
} else {
|
try {
|
||||||
const field = rel.checked.find((e) => !e.is_pk);
|
callback(await result);
|
||||||
if (field) {
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
local.status = "error";
|
||||||
|
toast.dismiss();
|
||||||
|
toast.error(
|
||||||
|
<div className="c-flex c-text-red-600 c-items-center">
|
||||||
|
<AlertTriangle className="c-h-4 c-w-4 c-mr-1" />
|
||||||
|
Failed to load data
|
||||||
|
</div>,
|
||||||
|
{
|
||||||
|
dismissible: true,
|
||||||
|
className: css`
|
||||||
|
background: #ffecec;
|
||||||
|
border: 2px solid red;
|
||||||
|
`,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
} else callback(result);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return local.reloading;
|
||||||
|
},
|
||||||
|
sort: {
|
||||||
|
columns: (ls_sort?.columns || []) as SortColumn[],
|
||||||
|
on_change: (cols: SortColumn[]) => {
|
||||||
|
if (feature?.find((e) => e === "sorting")) {
|
||||||
|
local.sort.columns = cols;
|
||||||
|
local.paging.skip = 0;
|
||||||
|
if (cols.length > 0) {
|
||||||
|
let { columnKey, direction } = cols[0];
|
||||||
|
|
||||||
|
if (columnKey.includes(".")) {
|
||||||
|
let root: any = {};
|
||||||
|
set(root, columnKey, direction === "ASC" ? "asc" : "desc");
|
||||||
|
local.sort.orderBy = root;
|
||||||
|
} else {
|
||||||
|
let should_set = true;
|
||||||
|
const gf = JSON.stringify(gen_fields);
|
||||||
|
const fields = fields_map.get(gf);
|
||||||
|
if (fields) {
|
||||||
|
const rel = fields?.find((e) => e.name === columnKey);
|
||||||
|
if (rel && rel.checked) {
|
||||||
|
should_set = false;
|
||||||
|
|
||||||
|
if (rel.type === "has-many") {
|
||||||
local.sort.orderBy = {
|
local.sort.orderBy = {
|
||||||
[columnKey]: {
|
[columnKey]: {
|
||||||
[field.name]: direction === "ASC" ? "asc" : "desc",
|
_count: direction === "ASC" ? "asc" : "desc",
|
||||||
},
|
|
||||||
};
|
|
||||||
} else if (rel.relation) {
|
|
||||||
local.sort.orderBy = {
|
|
||||||
[columnKey]: {
|
|
||||||
[rel.relation.to.fields[0]]:
|
|
||||||
direction === "ASC" ? "asc" : "desc",
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
} else {
|
||||||
|
const field = rel.checked.find((e) => !e.is_pk);
|
||||||
|
if (field) {
|
||||||
|
local.sort.orderBy = {
|
||||||
|
[columnKey]: {
|
||||||
|
[field.name]: direction === "ASC" ? "asc" : "desc",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
} else if (rel.relation) {
|
||||||
|
local.sort.orderBy = {
|
||||||
|
[columnKey]: {
|
||||||
|
[rel.relation.to.fields[0]]:
|
||||||
|
direction === "ASC" ? "asc" : "desc",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (should_set) {
|
if (should_set) {
|
||||||
local.sort.orderBy = {
|
local.sort.orderBy = {
|
||||||
[columnKey]: direction === "ASC" ? "asc" : "desc",
|
[columnKey]: direction === "ASC" ? "asc" : "desc",
|
||||||
};
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
local.sort.orderBy = null;
|
||||||
}
|
}
|
||||||
} else {
|
localStorage.setItem(
|
||||||
local.sort.orderBy = null;
|
`sort-${location.pathname}-${location.hash}-${name}`,
|
||||||
}
|
JSON.stringify({
|
||||||
localStorage.setItem(
|
columns: local.sort.columns,
|
||||||
`sort-${location.pathname}-${location.hash}-${name}`,
|
orderBy: local.sort.orderBy,
|
||||||
JSON.stringify({
|
})
|
||||||
columns: local.sort.columns,
|
);
|
||||||
orderBy: local.sort.orderBy,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
local.status = "reload";
|
local.status = "reload";
|
||||||
local.render();
|
local.render();
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
orderBy: (ls_sort?.orderBy || null) as null | Record<
|
||||||
|
string,
|
||||||
|
"asc" | "desc" | Record<string, "asc" | "desc">
|
||||||
|
>,
|
||||||
|
},
|
||||||
|
soft_delete: {
|
||||||
|
field: null as any,
|
||||||
},
|
},
|
||||||
orderBy: (ls_sort?.orderBy || null) as null | Record<
|
|
||||||
string,
|
|
||||||
"asc" | "desc" | Record<string, "asc" | "desc">
|
|
||||||
>,
|
|
||||||
},
|
},
|
||||||
soft_delete: {
|
({ setDelayedRender }) => {
|
||||||
field: null as any,
|
setDelayedRender(true);
|
||||||
},
|
}
|
||||||
});
|
);
|
||||||
|
|
||||||
const reload = local.reload;
|
const reload = local.reload;
|
||||||
if (md) {
|
if (md) {
|
||||||
|
md.master.list = local;
|
||||||
md.master.reload = reload;
|
md.master.reload = reload;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -712,9 +740,12 @@ export const TableList: FC<TableListProp> = ({
|
||||||
|
|
||||||
if (!isEditor) {
|
if (!isEditor) {
|
||||||
let should_toast = true;
|
let should_toast = true;
|
||||||
if (md && md.props.mode !== "full") {
|
if (md) {
|
||||||
should_toast = false;
|
if (md.props.mode !== "full") {
|
||||||
|
should_toast = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (should_toast) {
|
if (should_toast) {
|
||||||
if (local.status === "loading") {
|
if (local.status === "loading") {
|
||||||
toast.dismiss();
|
toast.dismiss();
|
||||||
|
|
@ -730,12 +761,6 @@ export const TableList: FC<TableListProp> = ({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (local.status === "resizing" && !isEditor) {
|
|
||||||
local.status = "ready";
|
|
||||||
local.render();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (document.getElementsByClassName("prasi-toaster").length === 0) {
|
if (document.getElementsByClassName("prasi-toaster").length === 0) {
|
||||||
const elemDiv = document.createElement("div");
|
const elemDiv = document.createElement("div");
|
||||||
elemDiv.className = "prasi-toaster";
|
elemDiv.className = "prasi-toaster";
|
||||||
|
|
@ -744,6 +769,11 @@ export const TableList: FC<TableListProp> = ({
|
||||||
const toaster_el = document.getElementsByClassName("prasi-toaster")[0];
|
const toaster_el = document.getElementsByClassName("prasi-toaster")[0];
|
||||||
|
|
||||||
if (mode === "table") {
|
if (mode === "table") {
|
||||||
|
if (local.status === "resizing" && !isEditor) {
|
||||||
|
local.status = "ready";
|
||||||
|
local.render();
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cx(
|
className={cx(
|
||||||
|
|
@ -929,7 +959,26 @@ export const TableList: FC<TableListProp> = ({
|
||||||
<Skeleton className={cx("c-w-[180px] c-h-[11px]")} />
|
<Skeleton className={cx("c-w-[180px] c-h-[11px]")} />
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="c-absolute c-inset-0">
|
<div
|
||||||
|
className={cx(
|
||||||
|
"c-absolute c-inset-0",
|
||||||
|
css`
|
||||||
|
@keyframes flasher {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(-10px);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.list-row {
|
||||||
|
animation: flasher 0.5s;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
>
|
||||||
<>
|
<>
|
||||||
{Array.isArray(data) && data.length > 0 ? (
|
{Array.isArray(data) && data.length > 0 ? (
|
||||||
<div
|
<div
|
||||||
|
|
@ -942,7 +991,7 @@ export const TableList: FC<TableListProp> = ({
|
||||||
{data.map((e, idx) => {
|
{data.map((e, idx) => {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="c-flex-grow c-flex"
|
className={cx("list-row c-flex-grow c-flex")}
|
||||||
onClick={(ev) => {
|
onClick={(ev) => {
|
||||||
if (!isEditor && typeof row_click === "function") {
|
if (!isEditor && typeof row_click === "function") {
|
||||||
row_click({
|
row_click({
|
||||||
|
|
@ -1047,9 +1096,14 @@ const genRows = (total: number) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const dataGridStyle = (local: { height: number }) => css`
|
const dataGridStyle = (local: { height: number }) => css`
|
||||||
.rdg {
|
${local.height
|
||||||
block-size: ${local.height}px;
|
? css`
|
||||||
}
|
.rdg {
|
||||||
|
block-size: ${local.height}px;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
: ``}
|
||||||
|
|
||||||
div[role="row"]:hover {
|
div[role="row"]:hover {
|
||||||
background: #e2f1ff;
|
background: #e2f1ff;
|
||||||
.num-edit {
|
.num-edit {
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,7 @@ export type MDLocalInternal = {
|
||||||
master: {
|
master: {
|
||||||
reload: (arg?: { toast: boolean }) => void;
|
reload: (arg?: { toast: boolean }) => void;
|
||||||
render: () => void;
|
render: () => void;
|
||||||
|
list?: any;
|
||||||
pk?: string;
|
pk?: string;
|
||||||
};
|
};
|
||||||
params: {
|
params: {
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ export const useLocal = <T extends object>(
|
||||||
data: T,
|
data: T,
|
||||||
effect?: (arg: {
|
effect?: (arg: {
|
||||||
init: boolean;
|
init: boolean;
|
||||||
|
setDelayedRender: (arg: boolean) => void;
|
||||||
}) => Promise<void | (() => void)> | void | (() => void),
|
}) => Promise<void | (() => void)> | void | (() => void),
|
||||||
deps?: any[]
|
deps?: any[]
|
||||||
): {
|
): {
|
||||||
|
|
@ -19,12 +20,20 @@ export const useLocal = <T extends object>(
|
||||||
_loading: {} as any,
|
_loading: {} as any,
|
||||||
lastRender: 0,
|
lastRender: 0,
|
||||||
lastRenderCount: 0,
|
lastRenderCount: 0,
|
||||||
|
delayedRender: false,
|
||||||
|
delayedRenderTimeout: null as any,
|
||||||
});
|
});
|
||||||
const local = _.current;
|
const local = _.current;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
local.ready = true;
|
local.ready = true;
|
||||||
if (effect) effect({ init: true });
|
if (effect)
|
||||||
|
effect({
|
||||||
|
init: true,
|
||||||
|
setDelayedRender(arg) {
|
||||||
|
local.delayedRender = arg;
|
||||||
|
},
|
||||||
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
if (local.ready === false) {
|
if (local.ready === false) {
|
||||||
|
|
@ -32,6 +41,17 @@ export const useLocal = <T extends object>(
|
||||||
|
|
||||||
local.data.render = () => {
|
local.data.render = () => {
|
||||||
if (local.ready) {
|
if (local.ready) {
|
||||||
|
if (local.delayedRender) {
|
||||||
|
if (Date.now() - local.lastRender > 100) {
|
||||||
|
local.lastRender = Date.now();
|
||||||
|
_render({});
|
||||||
|
} else {
|
||||||
|
clearTimeout(local.delayedRenderTimeout);
|
||||||
|
local.delayedRenderTimeout = setTimeout(local.data.render, 50);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (Date.now() - local.lastRender < 300) {
|
if (Date.now() - local.lastRender < 300) {
|
||||||
local.lastRenderCount++;
|
local.lastRenderCount++;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -39,7 +59,9 @@ export const useLocal = <T extends object>(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (local.lastRenderCount > 300) {
|
if (local.lastRenderCount > 300) {
|
||||||
throw new Error("local.render more than 300 times in less than 300ms");
|
throw new Error(
|
||||||
|
"local.render more than 300 times in less than 300ms"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
local.lastRender = Date.now();
|
local.lastRender = Date.now();
|
||||||
|
|
@ -54,7 +76,12 @@ export const useLocal = <T extends object>(
|
||||||
|
|
||||||
if (effect) {
|
if (effect) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
effect({ init: false });
|
effect({
|
||||||
|
init: false,
|
||||||
|
setDelayedRender(arg) {
|
||||||
|
local.delayedRender = arg;
|
||||||
|
},
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue