{"id":24488008,"url":"https://github.com/jay-ubisse/tanstack-query-table","last_synced_at":"2026-04-11T09:33:37.672Z","repository":{"id":273509967,"uuid":"919947683","full_name":"Jay-Ubisse/tanstack-query-table","owner":"Jay-Ubisse","description":"Este projeto demonstra como integrar as bibliotecas **TanStack Query** para buscar dados de uma API ou banco de dados e **TanStack Table** para exibir, filtrar e ordenar esses dados em uma tabela interativa.","archived":false,"fork":false,"pushed_at":"2025-01-31T09:15:59.000Z","size":44,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-31T10:23:23.690Z","etag":null,"topics":["css","reactjs","tanstack-react-query","tanstack-table","vite"],"latest_commit_sha":null,"homepage":"https://tanstack-query-table.vercel.app/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Jay-Ubisse.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2025-01-21T09:50:04.000Z","updated_at":"2025-01-31T09:16:03.000Z","dependencies_parsed_at":null,"dependency_job_id":"665a48f7-f230-4f3c-a0ec-f1f97df9c5f6","html_url":"https://github.com/Jay-Ubisse/tanstack-query-table","commit_stats":null,"previous_names":["jay-ubisse/tanstack-query-table"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Jay-Ubisse%2Ftanstack-query-table","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Jay-Ubisse%2Ftanstack-query-table/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Jay-Ubisse%2Ftanstack-query-table/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Jay-Ubisse%2Ftanstack-query-table/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Jay-Ubisse","download_url":"https://codeload.github.com/Jay-Ubisse/tanstack-query-table/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243663640,"owners_count":20327304,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["css","reactjs","tanstack-react-query","tanstack-table","vite"],"created_at":"2025-01-21T16:18:05.719Z","updated_at":"2026-04-11T09:33:37.623Z","avatar_url":"https://github.com/Jay-Ubisse.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Mini Projeto: Integração de TanStack Query e TanStack Table\n\nEste projeto demonstra como integrar as bibliotecas **TanStack Query** para buscar dados de uma API ou banco de dados e **TanStack Table** para exibir, filtrar e ordenar esses dados em uma tabela interativa.\n\n## Funcionalidades\n\n- Busca de dados usando o **TanStack Query**.\n- Exibição dos dados em uma tabela usando o **TanStack Table**.\n- Recursos de filtragem e ordenação na tabela.\n\n## Tecnologias Utilizadas\n\n- **React**: Framework principal para construção da interface.\n- **TanStack Query**: Gerenciamento de dados assíncronos (fetching e caching).\n- **TanStack Table**: Criação de tabelas avançadas e interativas.\n\n## Pré-requisitos\n\nCertifique-se de ter o seguinte instalado:\n\n- Node.js (v14 ou superior)\n- npm ou yarn\n\n## Configuração do Projeto\n\n1. Clone o repositório:\n\n   ```bash\n   git clone https://github.com/Jay-Ubisse/tanstack-query-table.git\n   cd tanstack-query-table\n   ```\n\n2. Instale as dependências:\n\n   ```bash\n   npm install\n   # ou\n   yarn install\n   ```\n\n3. Execute o projeto:\n\n   ```bash\n   npm run dev\n   # ou\n   yarn dev\n   ```\n\n4. Abra no navegador em `http://localhost:5173`.\n\n## Estrutura de Arquivos\n\n```plaintext\nsrc/\n├── components/table\n│   ├── table-instance.jsx   # Componente principal da tabela (usando Tanstack table)\n│   ├── index.jsx      # Componente para carregamento dos dados (usando Tanstack query)\n├── providers/\n│   ├── react-query.tsx # Hook para poder usar o react-query no projecto (usando no main.tsx)\n├── App.jsx             # Componente principal\n├── main.jsx            # Arquivo de entrada\n├── index.css           # Estilos globais\n```\n\n## Como Funciona\n\n### 1. Busca de Dados com TanStack Query\n\nUsamos o hook `useQuery` do TanStack Query para buscar dados de uma API:\n\n```javascript\nimport { useQuery } from \"@tanstack/react-query\";\nimport { getUsers } from \"../../services/users\";\nimport { TableInstance } from \"./table-instance\";\n\nexport function TanstckTable() {\n  const { isPending, error, data } = useQuery({\n    queryKey: [\"repoData\"],\n    queryFn: () =\u003e getUsers(),\n  });\n\n  if (isPending) return \"Loading...\";\n\n  if (error) return \"An error has occurred: \" + error.message;\n\n  if (!data || data.length === 0 || data.length \u003c 0)\n    return \"No available data to display\";\n\n  return (\n    \u003cdiv\u003e\n      \u003cTableInstance data={data} /\u003e\n    \u003c/div\u003e\n  );\n}\n```\n\n### 2. Configuração da Tabela com TanStack Table\n\nCriamos as colunas e definimos os dados para exibição:\n\n```javascript\nimport { useEffect, useMemo, useReducer, useState } from \"react\";\nimport {\n  Column,\n  ColumnDef,\n  ColumnFiltersState,\n  RowData,\n  flexRender,\n  getCoreRowModel,\n  getFilteredRowModel,\n  getPaginationRowModel,\n  getSortedRowModel,\n  useReactTable,\n} from \"@tanstack/react-table\";\nimport { UserProps } from \"../../types/users\";\n\ndeclare module \"@tanstack/react-table\" {\n  //allows us to define custom properties for our columns\n  interface ColumnMeta\u003cTData extends RowData, TValue\u003e {\n    filterVariant?: \"text\" | \"range\" | \"select\";\n  }\n}\n\nexport function TableInstance({ data }: { data: UserProps[] }) {\n  const [columnFilters, setColumnFilters] = useState\u003cColumnFiltersState\u003e([]);\n  const rerender = useReducer(() =\u003e ({}), {})[1];\n\n  const columns = useMemo\u003cColumnDef\u003cUserProps, any\u003e[]\u003e(\n    () =\u003e [\n      {\n        accessorKey: \"id\",\n        header: \"ID\",\n        cell: (info) =\u003e info.getValue(),\n      },\n      {\n        accessorFn: (row) =\u003e row.name,\n        id: \"name\",\n        cell: (info) =\u003e info.getValue(),\n        header: () =\u003e \u003cspan\u003eName\u003c/span\u003e,\n      },\n      {\n        accessorFn: (row) =\u003e row.email,\n        id: \"email\",\n        cell: (info) =\u003e info.getValue(),\n        header: () =\u003e \u003cspan\u003eEmail\u003c/span\u003e,\n      },\n      {\n        accessorFn: (row) =\u003e row.phone,\n        id: \"phone\",\n        cell: (info) =\u003e info.getValue(),\n        header: () =\u003e \u003cspan\u003ePhone\u003c/span\u003e,\n      },\n      {\n        accessorFn: (row) =\u003e row.website,\n        id: \"website\",\n        cell: (info) =\u003e info.getValue(),\n        header: () =\u003e \u003cspan\u003eWebsite\u003c/span\u003e,\n      },\n      {\n        accessorKey: \"username\",\n        header: \"Username\",\n        meta: {\n          filterVariant: \"select\",\n        },\n      },\n    ],\n    []\n  );\n\n  const table = useReactTable({\n    data,\n    columns,\n    filterFns: {},\n    state: {\n      columnFilters,\n    },\n    onColumnFiltersChange: setColumnFilters,\n    getCoreRowModel: getCoreRowModel(),\n    getFilteredRowModel: getFilteredRowModel(), //client side filtering\n    getSortedRowModel: getSortedRowModel(),\n    getPaginationRowModel: getPaginationRowModel(),\n    debugTable: true,\n    debugHeaders: true,\n    debugColumns: false,\n  });\n\n  return (\n    \u003cdiv className=\"p-2\"\u003e\n      \u003ctable\u003e\n        \u003cthead\u003e\n          {table.getHeaderGroups().map((headerGroup) =\u003e (\n            \u003ctr key={headerGroup.id}\u003e\n              {headerGroup.headers.map((header) =\u003e {\n                return (\n                  \u003cth key={header.id} colSpan={header.colSpan}\u003e\n                    {header.isPlaceholder ? null : (\n                      \u003c\u003e\n                        \u003cdiv\n                          {...{\n                            className: header.column.getCanSort()\n                              ? \"cursor-pointer select-none\"\n                              : \"\",\n                            onClick: header.column.getToggleSortingHandler(),\n                          }}\n                        \u003e\n                          {flexRender(\n                            header.column.columnDef.header,\n                            header.getContext()\n                          )}\n                          {{\n                            asc: \" 🔼\",\n                            desc: \" 🔽\",\n                          }[header.column.getIsSorted() as string] ?? null}\n                        \u003c/div\u003e\n                        {header.column.getCanFilter() ? (\n                          \u003cdiv\u003e\n                            \u003cFilter column={header.column} /\u003e\n                          \u003c/div\u003e\n                        ) : null}\n                      \u003c/\u003e\n                    )}\n                  \u003c/th\u003e\n                );\n              })}\n            \u003c/tr\u003e\n          ))}\n        \u003c/thead\u003e\n        \u003ctbody\u003e\n          {table.getRowModel().rows.map((row) =\u003e {\n            return (\n              \u003ctr key={row.id}\u003e\n                {row.getVisibleCells().map((cell) =\u003e {\n                  return (\n                    \u003ctd key={cell.id}\u003e\n                      {flexRender(\n                        cell.column.columnDef.cell,\n                        cell.getContext()\n                      )}\n                    \u003c/td\u003e\n                  );\n                })}\n              \u003c/tr\u003e\n            );\n          })}\n        \u003c/tbody\u003e\n      \u003c/table\u003e\n      \u003cdiv className=\"h-2\" /\u003e\n      \u003cdiv className=\"flex items-center gap-2\"\u003e\n        \u003cbutton\n          className=\"border rounded p-1\"\n          onClick={() =\u003e table.setPageIndex(0)}\n          disabled={!table.getCanPreviousPage()}\n        \u003e\n          {\"\u003c\u003c\"}\n        \u003c/button\u003e\n        \u003cbutton\n          className=\"border rounded p-1\"\n          onClick={() =\u003e table.previousPage()}\n          disabled={!table.getCanPreviousPage()}\n        \u003e\n          {\"\u003c\"}\n        \u003c/button\u003e\n        \u003cbutton\n          className=\"border rounded p-1\"\n          onClick={() =\u003e table.nextPage()}\n          disabled={!table.getCanNextPage()}\n        \u003e\n          {\"\u003e\"}\n        \u003c/button\u003e\n        \u003cbutton\n          className=\"border rounded p-1\"\n          onClick={() =\u003e table.setPageIndex(table.getPageCount() - 1)}\n          disabled={!table.getCanNextPage()}\n        \u003e\n          {\"\u003e\u003e\"}\n        \u003c/button\u003e\n        \u003cspan className=\"flex items-center gap-1\"\u003e\n          \u003cdiv\u003ePage\u003c/div\u003e\n          \u003cstrong\u003e\n            {table.getState().pagination.pageIndex + 1} of{\" \"}\n            {table.getPageCount()}\n          \u003c/strong\u003e\n        \u003c/span\u003e\n        \u003cspan className=\"flex items-center gap-1\"\u003e\n          | Go to page:\n          \u003cinput\n            type=\"number\"\n            min=\"1\"\n            max={table.getPageCount()}\n            defaultValue={table.getState().pagination.pageIndex + 1}\n            onChange={(e) =\u003e {\n              const page = e.target.value ? Number(e.target.value) - 1 : 0;\n              table.setPageIndex(page);\n            }}\n            className=\"border p-1 rounded w-16\"\n          /\u003e\n        \u003c/span\u003e\n        \u003cselect\n          value={table.getState().pagination.pageSize}\n          onChange={(e) =\u003e {\n            table.setPageSize(Number(e.target.value));\n          }}\n        \u003e\n          {[10, 20, 30, 40, 50].map((pageSize) =\u003e (\n            \u003coption key={pageSize} value={pageSize}\u003e\n              Show {pageSize}\n            \u003c/option\u003e\n          ))}\n        \u003c/select\u003e\n      \u003c/div\u003e\n      \u003cdiv\u003e{table.getPrePaginationRowModel().rows.length} Rows\u003c/div\u003e\n      \u003cdiv\u003e\n        \u003cbutton onClick={() =\u003e rerender()}\u003eForce Rerender\u003c/button\u003e\n      \u003c/div\u003e\n      \u003cdiv\u003e\n        \u003cbutton onClick={() =\u003e console.log(\"Add a function to refresh data\")}\u003e\n          Refresh Data\n        \u003c/button\u003e\n      \u003c/div\u003e\n      \u003cpre\u003e\n        {JSON.stringify(\n          { columnFilters: table.getState().columnFilters },\n          null,\n          2\n        )}\n      \u003c/pre\u003e\n    \u003c/div\u003e\n  );\n}\n\nfunction Filter({ column }: { column: Column\u003cany, unknown\u003e }) {\n  const columnFilterValue = column.getFilterValue();\n  const { filterVariant } = column.columnDef.meta ?? {};\n\n  return filterVariant === \"range\" ? (\n    \u003cdiv\u003e\n      \u003cdiv className=\"flex space-x-2\"\u003e\n        {/* See faceted column filters example for min max values functionality */}\n        \u003cDebouncedInput\n          type=\"number\"\n          value={(columnFilterValue as [number, number])?.[0] ?? \"\"}\n          onChange={(value) =\u003e\n            column.setFilterValue((old: [number, number]) =\u003e [value, old?.[1]])\n          }\n          placeholder={`Min`}\n          className=\"w-24 border shadow rounded\"\n        /\u003e\n        \u003cDebouncedInput\n          type=\"number\"\n          value={(columnFilterValue as [number, number])?.[1] ?? \"\"}\n          onChange={(value) =\u003e\n            column.setFilterValue((old: [number, number]) =\u003e [old?.[0], value])\n          }\n          placeholder={`Max`}\n          className=\"w-24 border shadow rounded\"\n        /\u003e\n      \u003c/div\u003e\n      \u003cdiv className=\"h-1\" /\u003e\n    \u003c/div\u003e\n  ) : filterVariant === \"select\" ? (\n    \u003cselect\n      onChange={(e) =\u003e column.setFilterValue(e.target.value)}\n      value={columnFilterValue?.toString()}\n    \u003e\n      {/* See faceted column filters example for dynamic select options */}\n      \u003coption value=\"\"\u003eAll\u003c/option\u003e\n      \u003coption value=\"Samantha\"\u003eSamantha\u003c/option\u003e\n      \u003coption value=\"Bret\"\u003eBret\u003c/option\u003e\n      \u003coption value=\"Antonette\"\u003eAntonette\u003c/option\u003e\n    \u003c/select\u003e\n  ) : (\n    \u003cDebouncedInput\n      className=\"w-36 border shadow rounded\"\n      onChange={(value) =\u003e column.setFilterValue(value)}\n      placeholder={`Search...`}\n      type=\"text\"\n      value={(columnFilterValue ?? \"\") as string}\n    /\u003e\n    // See faceted column filters example for datalist search suggestions\n  );\n}\n\n// A typical debounced input react component\nfunction DebouncedInput({\n  value: initialValue,\n  onChange,\n  debounce = 500,\n  ...props\n}: {\n  value: string | number;\n  onChange: (value: string | number) =\u003e void;\n  debounce?: number;\n} \u0026 Omit\u003cReact.InputHTMLAttributes\u003cHTMLInputElement\u003e, \"onChange\"\u003e) {\n  const [value, setValue] = useState(initialValue);\n\n  useEffect(() =\u003e {\n    setValue(initialValue);\n  }, [initialValue]);\n\n  useEffect(() =\u003e {\n    const timeout = setTimeout(() =\u003e {\n      onChange(value);\n    }, debounce);\n\n    return () =\u003e clearTimeout(timeout);\n  }, [value]);\n\n  return (\n    \u003cinput\n      {...props}\n      value={value}\n      onChange={(e) =\u003e setValue(e.target.value)}\n    /\u003e\n  );\n}\n\n```\n\n### 3. Integração no Componente Principal\n\n```javascript\nimport { TanstckTable } from \"./components/table\";\n\nfunction App() {\n  return (\n    \u003c\u003e\n      \u003cTanstckTable /\u003e\n    \u003c/\u003e\n  );\n}\n\nexport default App;\n```\n\n## Recursos Adicionais\n\n- [TanStack Query Documentation](https://tanstack.com/query/latest/docs/framework/react/overview)\n- [TanStack Table Documentation](https://tanstack.com/table/latest/docs/introduction)\n- [Vite Documentation](https://vitejs.dev/)\n\n---\n\n[Link para visualização do projecto](https://tanstack-query-table.vercel.app/)\nDesenvolvido com ❤️ por [Jay-Ubisse](https://github.com/Jay-Ubisse/).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjay-ubisse%2Ftanstack-query-table","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjay-ubisse%2Ftanstack-query-table","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjay-ubisse%2Ftanstack-query-table/lists"}