Modern app data can get complex, and efficiently connecting your frontend application to your backend data is crucial for building responsive user experiences. Firebase Data Connect already offers a powerful way to model, query, and mutate your structured data using GraphQL schemas directly within your Firebase project. Building on that foundation, we’re excited to introduce preview bindings for Angular and React that make integrating Firebase Data Connect into your web applications smoother than ever! These bindings leverage the popular TanStack Query library (v5) to streamline data fetching, caching, and state management, letting you focus more on crafting your app’s UI and less on data plumbing.
The Core Idea: Type-Safe Data Management with TanStack Query
Consider your Data Connect schemas as the blueprint for your app’s structured data. You define types like Movie or User with specific fields and relationships in your schema.graphql (or similar .gql
files):
type Movie @table(name: "Movies") {
id: UUID! @default(expr: "uuidV4()")
title: String!
releaseYear: Int @index
rating: Int
description: String
}
Your app may also have queries in query.gql
such as:
query ListMovies($orderByRating: OrderDirection, $orderByReleaseYear: OrderDirection, $limit: Int) @auth(level: PUBLIC) {
movies(
orderBy: [
{ rating: $orderByRating },
{ releaseYear: $orderByReleaseYear }
]
limit: $limit
) {
id
title
description
}
}
query GetActorById($id: UUID!) @auth(level: PUBLIC) {
actor(id: $id) {
id
name
imageUrl
mainActors: movies_via_MovieActor(where: { role: { eq: "main" } }) {
id
title
}
supportingActors: movies_via_MovieActor(
where: { role: { eq: "supporting" } }
) {
id
title
}
}
}
Previously, you’d use the generated Data Connect SDK functions directly, often wrapping them in services or custom hooks. The new bindings automate much of this boilerplate.
By enabling the relevant flag (react: true
or angular: true
) in your connector.yaml
and running firebase dataconnect:sdk:generate
, the bindings will:
Generate Type-Safe Hooks (React) or Injectors (Angular): Based on the queries and mutations defined in your GraphQL schema.
Integrate with TanStack Query: Provide functions that automatically wrap your Data Connect operations with TanStack Query’s useQuery, useMutation, etc.
Let’s see how to set it up.
Use Angular bindings
1. Setup
Enable Angular SDK Generation: Add angular: true
under javascriptSdk
in your connector.yaml
:
generate:
javascriptSdk:
package: "@movie/dataconnect"
outputDir: ../../src/lib/dataconnect-sdk
packageJsonDir: "../../"
angular: true
2. Install Dependencies
Add TanStack Query for Angular and the Firebase Data Connect Angular bindings:
npm i --save @tanstack/angular-query @tanstack-query-firebase/angular
3. Provide Query Client
Configure TanStack Query in your application’s providers, typically in app.config.ts
:
// app.config.ts
import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router';
import { routes } from './app.routes';
import { provideTanStackQuery, QueryClient } from "@tanstack/angular-query";
// Create a single QueryClient instance
const queryClient = new QueryClient();
export const appConfig: ApplicationConfig = {
providers: [
provideRouter(routes),
// Add the TanStack Query provider
provideTanStackQuery(queryClient),
]
};
4. Emulator Setup
Open the Firebase Data Connect VS Code Extension panel. Select your Firebase project. Click “Start Emulators”.
5. Usage
Use the generated injectors directly in your components:
// movie-list.component.ts
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
// Generated based on your schema (adjust path relative to your component)
import { injectListMovies } from '@movie/dataconnect/angular';
import { OrderDirection } from '@movie/dataconnect'; // Generated Enums/Types
import { MovieCardComponent } from '../movie-card/movie-card.component'; // Your UI component
@Component({
selector: 'app-movie-list',
standalone: true,
imports: [CommonModule, MovieCardComponent],
template: `
<h2>Top Rated Movies</h2>
<!-- Use TanStack Query state signals directly in the template -->
@if(top10Movies.isPending()) {
<div>Loading movies...</div>
}
@if(top10Movies.isError()) {
<div>Error loading movies: {{ top10Movies.error()?.message }}</div>
}
@if(top10Movies.data(); as movies) {
<div class="movie-grid">
@for(movie of movies; track movie.id) {
<app-movie-card [movie]="movie"/>
} @empty {
<div>No movies found.</div>
}
</div>
}
`,
// Add styles as needed
})
export class MovieListComponent {
// Inject the query function directly. It returns a TanStack Query Result Signal.
top10Movies = injectListMovies({ limit: 10, orderByRating: OrderDirection.DESC });
// The 'top10Movies' signal contains properties like:
// data(): TData | undefined
// error(): TError | null
// isPending(): boolean
// isSuccess(): boolean
// ...and more TanStack Query state flags.
}
Using React bindings:
1. Setup
Enable React SDK Generation: Add react: true
under javascriptSdk
in your connector.yaml
:
generate:
javascriptSdk:
package: "@movie/dataconnect"
outputDir: ../../src/lib/dataconnect-sdk
packageJsonDir: "../../"
react: true
2. Configure TypeScript
Ensure your tsconfig.json uses modern module resolution suitable for the generated SDK:
// tsconfig.json
{
"compilerOptions": {
"module": "ESNext",
"moduleResolution": "bundler",
},
}
3. Install Dependencies
Add TanStack Query for React and the Firebase Data Connect React bindings:
npm i --save @tanstack/react-query @tanstack-query-firebase/react
4. Provide Query Client
Wrap your application root (or the relevant part using queries) with QueryClientProvider:
// src/main.tsx (or index.tsx, App.tsx depending on setup)
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App'; // Your main App component
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import './index.css';
// Create a client instance
const queryClient = new QueryClient();
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>
</React.StrictMode>,
);
5. Usage
// src/pages/ActorPage.tsx (Example component)
import React from 'react';
import { useParams } from 'react-router-dom';
// Generated based on your schema (adjust path relative to your component)
import { useGetActorById } from '@movie/dataconnect/react'; // Import the generated hook
function ActorPage() {
const { id } = useParams<{ id: string }>();
const { data: actor, isLoading, error, isSuccess } = useGetActorById(
{ id: id! }
);
if (isLoading) {
return <div>Loading actor details...</div>;
}
if (error) {
return <div>Error loading actor: {error.message}</div>;
}
if (isSuccess) {
return (
<div>
<h1>{actor.name}</h1>
<p>Bio: {actor.bio || 'N/A'}</p>
</div>
);
}
return <div>Actor not found or ID is missing.</div>;
}
export default ActorPage;
The hook (useGetActorById
) returns the standard TanStack Query result object, providing loading states, error objects, and type-safe data directly from your Data Connect schema.
Why Use the New Bindings?
- Reduced Boilerplate: Less manual setup for data fetching, loading, and error handling.
- Type Safety: End-to-end type safety from your GraphQL schema to your component props and state.
- Performance: Automatic caching, request deduplication, and background updates via TanStack Query.
- Developer Experience: Work with familiar patterns (React Hooks, Angular Injectors/Signals) tailored for Data Connect.
Get Started Today!
Explore the official Firebase Data Connect documentation and the rich TanStack Query documentation (switch framework for Angular details) to learn more. We’re eager to see the amazing, data-driven applications you build with these new capabilities, and your feedback is invaluable – please share your experiences and feature requests!