Wire Up useQuery

We have a query on the server. Let’s use it in our React app.

The useQuery Hook

Convex provides a useQuery hook that subscribes to a query and returns the latest results. It works like TanStack Query’s useQuery. The difference is that it stays subscribed, so when the data changes on the server, the component re-renders automatically.

Update KanbanBoard

Replace the contents of src/components/kanban-board.tsx:

import { useQuery } from "convex/react";
import { api } from "../../convex/_generated/api";
import Column from "@/components/column";
import AddTaskDialog from "@/components/add-task-dialog";

type TaskStatus = "todo" | "in-progress" | "done";

const COLUMNS: { title: string; status: TaskStatus }[] = [
  { title: "To Do", status: "todo" },
  { title: "In Progress", status: "in-progress" },
  { title: "Done", status: "done" },
];

function KanbanBoard() {
  const tasks = useQuery(api.tasks.list);

  if (tasks === undefined) {
    return <p className="text-muted-foreground">Loading tasks...</p>;
  }

  return (
    <div>
      <div className="mb-6 flex justify-end">
        <AddTaskDialog />
      </div>
      <div className="grid grid-cols-1 gap-6 md:grid-cols-3">
        {COLUMNS.map((column) => (
          <Column
            key={column.status}
            title={column.title}
            status={column.status}
            tasks={tasks.filter((task) => task.status === column.status)}
          />
        ))}
      </div>
    </div>
  );
}

export default KanbanBoard;

The key changes:

  • useQuery(api.tasks.list) replaces useStore(taskStore, ...). The api.tasks.list reference is the typed path to our query. Convex generated it from the file name (tasks.ts) and export name (list). We import the api object from the generated API file, which contains all the queries and mutations with correct types.

  • tasks === undefined: useQuery returns undefined while the first result is loading. After that, it always has data. We show a loading message until the data arrives.

  • TaskStatus is defined locally: we no longer import it from the store. This is the same type, just defined here since the board needs it for the column definitions.

Checkpoint: Commit your progress.

git add .
git commit -m "kanban-05: Wire up useQuery to read tasks from Convex"
git push