October 9, 2023Marcus Hellberg

Tutorial: Integrating React Query with Hilla for Type-Safe Backend Services

In this hands-on tutorial, we will delve into using React Query with Hilla to connect to Spring Boot through type-safe backend services. We will be creating a simple Hilla application that integrates React Query on the frontend. As we walk through the process, you'll gain an understanding of how to build fast, efficient, and type-safe applications using Java and TypeScript.

Prerequisites

Before diving in, make sure you have a basic understanding of React, Java, and Spring Boot. A little familiarity with TypeScript will also be helpful.

Step 1: Setting Up the Application

Let's kick things off by setting up our backend. For our demonstration, we'll create a simple Todo entity and a TodoRepository to save these entities to a database. Here's what our basic Todo entity looks like:

@Entity
public class Todo {
    @Id
    @GeneratedValue
    private Long id;
    private String task;

    // getters, setters
}

And our TodoRepository is a simple Spring Boot repository:

public interface TodoRepository extends JpaRepository<Todo, Long> {}

Next, we'll create a TodoService class. This is a browser-callable service that fetches all todos and saves a todo:

@BrowserCallable
@AnonymousAllowed
public class TodoService {
    private final TodoRepository todoRepository;

    public TodoService(TodoRepository todoRepository) {
        this.todoRepository = todoRepository;
    }

    public List<Todo> getTodos() {
        return todoRepository.findAll();
    }

    public Todo save(Todo todo) {
        return todoRepository.save(todo);
    }
}

Step 2: Installing React Query

Now, let's integrate React Query into our project. Visit the TanStack React Query website and locate the npm install instruction. Open your terminal, navigate to the root of your project, and run the following command:

npm i @tanstack/react-query

Step 3: Setting Up the Query Client Provider

With React Query installed, we need to set up a query client and wrap our application with it. This is done in the App.tsx file:

import { QueryClient, QueryClientProvider } from "@tanstack/react-query";

const queryClient = new QueryClient();

export default function App() {
  return (
    <QueryClientProvider client={queryClient}>
      // Your application code here
    </QueryClientProvider>
  );
}

Step 4: Using React Query and Hilla in Our View

Now that our query client provider is set up, navigate to your view (we'll use HelloWorldView.tsx for this tutorial).

We'll start by importing the necessary modules:

import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { TodoService } from "Frontend/generated/endpoints";
import { useForm } from "@hilla/react-form";
import TodoModel from "Frontend/generated/com/example/application/db/TodoModel";
import { TextField } from "@hilla/react-components/TextField";
import { Button } from "@hilla/react-components/Button";

Next, we'll set up our queries and mutations using React Query hooks and our TodoService. We'll use the useForm hook from Hilla to create a form for adding new todos:

export default function HelloWorldView() {
  const queryClient = useQueryClient();

  const query = useQuery({
    queryKey: ["todos"],
    queryFn: TodoService.getTodos,
  });

  const mutation = useMutation({
    mutationFn: TodoService.save,
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ["todos"] });
    },
  });

  const { model, field, submit } = useForm(TodoModel, {
    onSubmit: async (todo) => mutation.mutate(todo),
  });

Finally, we'll build out our UI. We'll create a form for adding new todos and a list for displaying all existing todos:

  return (
    <div className="p-m">
      <h1>Hilla todo</h1>
      <div className="flex gap-m">
        <TextField {...field(model.task)} />
        <Button onClick={submit}>Add todo</Button>
      </div>

      <ul>
        {query.data?.map((todo) => (
          <li key={todo.id}>{todo.task}</li>
        ))}
      </ul>
    </div>
  );
}

And that's it! You've successfully integrated React Query with Hilla for type-safe backend services. Refresh your browser and test out your new application. Enjoy the full type safety experience from backend to frontend, powered by Java and TypeScript!

Marcus Hellberg

Marcus Hellberg

Marcus is the VP of Developer Relations at Vaadin. His daily work includes everything from writing blogs and tech demos to attending events and giving presentations on all things Vaadin and web-related.

© 2024 Vaadin. All rights reserved