# useObjectList (https://v1.s3.dimah.dev/docs/react/hooks/object-list)

`useObjectList` keeps the current folder, the breadcrumb, and cursor
pagination. It does not know where the rows live and it does not call S3.
You pass a `query` function.

```tsx title="components/file-browser.tsx"
"use client";

import { useObjectList } from "@dimah-s3/react";

export function FileBrowser() {
  const list = useObjectList({
    query: ({ parent, cursor, signal }) =>
      fetch(`/api/files?folder=${parent ?? ""}&cursor=${cursor ?? ""}`, {
        signal,
      }).then((response) => response.json()),
    queryKey: ["files"],
  });

  return (
    <ul>
      {list.folders.map((folder) => (
        <li key={folder.id}>
          <button type="button" onClick={() => list.openFolder(folder)}>
            {folder.name}
          </button>
        </li>
      ))}
      {list.items.map((file) => (
        <li key={file.id}>{file.name}</li>
      ))}
    </ul>
  );
}
```

The query receives:

- `parent` — folder id, or `null` at the root. The id is opaque. A database id, a path, or a key prefix are all valid.
- `cursor` — `null` on the first page. Return `nextCursor: null` on the last page.
- `signal` — aborted when the folder changes, `refresh()` runs, or the hook unmounts.

Return `folders` only from the first page. Later pages append `items`. Changing `queryKey` clears the list and loads the first page again. Use it for filters such as the route name.

Omit `parent` and the hook owns navigation. Pass `parent` and `onParentChange` together when the URL owns it. `parent={null}` is the controlled root. `defaultTrail` labels the starting path. The last id should match `defaultParent`.

```tsx
const list = useObjectList({
  query,
  parent: folderId,
  onParentChange: setFolderId,
});
```

`readObjectListLevel` splits a flat list into the folders and files at one level. `getFolder` returns a `/`-separated path, or `null` for the root. Pass the full set for that listing. A single page of a database query cannot be grouped after the fact. A paged tree returns `folders` from your own query. See [Folders](https://v1.s3.dimah.dev/docs/react/ui/components/object-list#folders).

```ts
import { readObjectListLevel } from "@dimah-s3/react";

const level = readObjectListLevel(records, {
  parent,
  getFolder: (record) => record.folder,
});
```

## With `db()` [#with-db]

`dbObjectQuery` adapts `api.db.listObjects` for a flat catalog. `parent` is sent as the key `prefix`. The adapter does not invent folder rows: generated keys contain a uuid segment, so splitting the key is not a folder tree. `dbObjectListAccessors` maps each row onto `ObjectList`: row id, object key, filename, content type, and verified size.

```tsx title="components/db-files.tsx"
"use client";

import {
  dbClient,
  dbObjectListAccessors,
  dbObjectQuery,
} from "@dimah-s3/db/client";
import { createS3Client, useObjectList } from "@dimah-s3/react";
import { ObjectList } from "@dimah-s3/ui";

const s3Client = createS3Client({
  basePath: "/api/s3",
  plugins: [dbClient()],
});

export function DbFiles() {
  const api = s3Client.useApi();
  const list = useObjectList({
    query: dbObjectQuery(api.db.listObjects, { route: "docs" }),
    queryKey: ["docs"],
  });
  const files = dbObjectListAccessors();

  return <ObjectList list={list} {...files} />;
}
```

Scope still comes from the server `resolveScope`. The query does not accept a scope.

## UI [#ui]

[`ObjectList`](https://v1.s3.dimah.dev/docs/react/ui/components/object-list) renders this state. Pass `upload` on that component to drop or paste files into the open folder. Pass `usage` from the query and `usageLimits` on the component to show how full the catalog is. It does not call the hook. Skip it and render `list.items` yourself when you want different markup.

## Props [#props]

```ts
import type {
  UseObjectListOptions,
  UseObjectListReturn,
} from "@dimah-s3/react";
```

<AutoTypeTable
  path="packages/react/src/list/types.ts"
  name="UseObjectListOptions"
/>

<AutoTypeTable
  path="packages/react/src/hooks/use-object-list.ts"
  name="UseObjectListReturn"
/>
