SolidJSS
SolidJSโ€ข9mo agoโ€ข
6 replies
cRambo

SolidTable infinite loop with `createAsync` query, createMemo but not createSignal + createEffect?

I'm writing a SolidStart project, using SolidTable to display data from a backend DB. I'm using SolidStart query to fetch data and SolidStart actions to insert data. I'm running into an issue where if I supply the createAsync accessor of the query directly as the
data
parameter for the table - it hangs / hits out of memory errors when I insert a row using the action. I'm not 100% sure what causes the issue but it seems like it might be an infinite re-render of the table. If I keep everything the same but change the table data to be an empty array then it works no problems - so not an issue with the DB/query/action by themselves, it's only when its used as data for the table.

I've tried some alternative approaches - createMemo of the createAsync accessor does not work - but strangely if I use createSignal and then update it with the value of the createAsync query in createEffect then it does work? Why createSignal/createEffect here work when createAsync does not? Does createAsync not have stable references?

Please help me work this out - I'd really like to not use createEffect to make this work if I can avoid it. Thanks!

const getTests = query(async () => {
  "use server";
  const db = new Kysely<DB>({ dialect });
  return await db.selectFrom("tests").selectAll().execute();
}, "getTests");

const addTest = action(async (formData: FormData) => {
  "use server";
  const db = new Kysely<DB>({ dialect });
  const values: InsertableTest = {
    // ...
  };
  await db.insertInto("tests").values(values).execute();
});

export const route = {
  preload() {
    getTests();
  },
} satisfies RouteDefinition;

export default function TestView() {
  const addTestAction = useAction(addTest);
  const submission = useSubmission(addTest);

  // 1. The `createAsync` accessor for the query DOES NOT work!
  const data = createAsync<InsertableTest[]>(async () => await getTests());

  // 2. Memoization of the `createAsync` query DOES NOT work!
  const tableMemo = createMemo(() => data() ?? []);

  // 3. Signal updated via `createEffect` DOES work?
  const [tableData, setTableData] = createSignal<InsertableTest[]>([]);
  createEffect(() => {
    setTableData(data() ?? []);
  });

  return (
    <div>
      <DataTable columns={columns} data={data()} />
      <Button
        disabled={submission.pending}
        onClick={() => {
          const formData = new FormData();
          // formData.append(...);
          addTestAction(formData);
        }}
      >
        Insert Test
      </Button>
    </div>
  );
}

interface DataTableProps<TData, TValue> {
  columns: ColumnDef<TData, TValue>[];
  data: TData[] | undefined;
}

export function DataTable<TData, TValue>(props: DataTableProps<TData, TValue>) {
  const table = createSolidTable({
    get data() {
      return props.data ?? [];
    },
    get columns() {
      return props.columns;
    },
    getCoreRowModel: getCoreRowModel(),
    getPaginationRowModel: getPaginationRowModel(),
  });
  table.setPageSize(20);
// ...
Was this page helpful?