Create your own
Lesson illustration

React Hook to HTMX: Data Fetching Translation

Welcome to the next step in our migration journey. In our last lesson, we successfully replaced client-side routing with a robust server-driven navigation system using Express and HTMX. You now have a solid multi-page application foundation that provides an SPA-like feel through partial content swaps.

Today, we will address one of the most common patterns in any modern web application: fetching and displaying data. Your learning goal is to translate the familiar React data-fetching hook pattern—useEffect combined with fetch—into its direct HTMX equivalent. This involves using hx-get to request data and building a corresponding "fragment endpoint" on the server that returns HTML instead of JSON. This is a pivotal step in moving from a client-side rendering model to a hypermedia-driven one.

From useEffect to hx-get

In your React applications, a standard pattern for loading data into a component looks something like this:

  1. A component mounts.
  2. A useEffect hook fires.
  3. Inside the hook, fetch calls a JSON API endpoint.
  4. You manage loading, error, and data states with useState.
  5. When the JSON data arrives, you update the state, triggering a re-render where React's rendering logic turns that data into DOM nodes.

HTMX radically simplifies this by delegating the rendering logic to the server. The entire client-side state management and rendering boilerplate is replaced by a few declarative HTML attributes.

The article "The HTML-First Approach" provides a striking side-by-side comparison that perfectly illustrates this simplification.

The HTML-First Approach: Why htmx and Lightweight Frameworks Are Revolutionizing Web Development · while true do;

This article provides a direct, code-level comparison between the verbose JavaScript needed in a traditional SPA and the concise markup of an HTML-first approach with HTMX.

In the article, find the section titled "A Practical Example". Carefully compare the React code block for the LoadDataButton with the HTMX version just below it. Notice how the multiple useState hooks, the async handler, and the conditional rendering logic in React are all collapsed into a single <button> element with a few hx- attributes.

As you can see, the complex client-side logic is replaced by a simple declaration: "When this element is triggered, GET content from /data and put it into the element with the ID #result." This is the core mental shift: you are no longer fetching data and rendering it; you are fetching rendered HTML.

The Server's New Role: The Fragment Endpoint

This declarative approach on the front end requires a corresponding change on the back end. The endpoint specified in hx-get (e.g., /data) cannot be a traditional JSON API. It must be what we call a fragment endpoint. Its sole responsibility is to fetch the necessary data, render just the required piece of HTML (a "partial"), and send that HTML fragment back in the response.

The "htmx and Alpine.js" tutorial provides a clear example of building these endpoints in an Express application. Let's look at how a server-side search endpoint is constructed.

htmx and Alpine.js: Build Interactive Web Apps Without Heavy JavaScript Frameworks

This tutorial demonstrates a complete, working example of an Express server designed to work with HTMX. We will focus on a specific route that acts as a fragment endpoint.

In the server.js code block, locate the route handler for searching tasks. Observe the final line: res.render("partials/task-list", { tasks: filtered });. This is the key. Instead of res.json(filtered), the server is using the templating engine to render an EJS partial with the filtered data and sending the resulting HTML string as the response.

This endpoint perfectly embodies the hypermedia principle. The client doesn't need to know how to render a list of tasks; it only needs to know where to request the list and where to place the result.

Connecting the Client and Server

Now that we've seen the front-end attributes and the back-end endpoint, let's see how they work together. The same tutorial shows the client-side markup that consumes the search endpoint we just examined. This example implements a live search field—a feature that would require significant client-side code in React.

htmx and Alpine.js: Build Interactive Web Apps Without Heavy JavaScript Frameworks

This part of the tutorial shows the HTML that makes the request to the fragment endpoint.

First, look at the views/index.ejs code. Find the <input type="search"> element within the <tf start="<div class="search-bar">" end="Searching...">search bar. Note the hx-get, hx-target, and hx-trigger attributes. The hx-trigger attribute is particularly interesting, as it's configured to fire the request automatically as the user types, with a 300ms debounce. Next, read the breakdown that immediately follows, which explains what each attribute does. Finally, glance at the views/partials/task-list.ejs template mentioned in the next section. This is the actual HTML fragment that the server renders and sends back to be swapped into the #task-list div.

This complete example—from the user's input to the server-side rendering and back to the DOM swap—is the canonical pattern for translating a useEffect-based data fetch into HTMX.

Visualizing the Payoff

To reinforce this new model and highlight the benefits you're working towards, the following video from Jack Herrington provides a great summary for developers coming from React. He rebuilds a simple pagination feature in HTMX and then compares the network traffic and bundle size against an equivalent React implementation.

HTMX For React Developers in 10 Minutes

This video provides a rapid, developer-focused overview of HTMX from a React perspective, culminating in a direct comparison of the two approaches.

First, watch the segment from the start of the demo. This serves as a quick recap, showing the hx-get/hx-target pattern being used to fetch paginated data. The backend here uses Astro, but the principle of rendering a partial is identical to our Express setup. Then, jump to the comparison segment from this timestamp. Pay close attention to the developer tools. On the React side, you see JSON payloads. On the HTMX side, you see small HTML fragments. The final comparison of the total JavaScript payload makes the primary motivation for this migration tangible.

The dramatic reduction in client-side JavaScript for this common use case is a compelling argument for the hypermedia approach, especially for the CRUD-style applications you are targeting.

Conclusion

In this lesson, you have learned how to translate one of React's most fundamental patterns into the HTMX paradigm. You've moved from writing imperative JavaScript code to fetch JSON and manage state, to writing declarative HTML attributes that request pre-rendered fragments from the server.

Key Takeaways:

  • Pattern Translation: The useEffect + fetch + useState pattern in React is replaced by the declarative hx-get and hx-target attributes in HTMX.
  • The Fragment Endpoint: HTMX requests are served by special backend endpoints that render and return HTML partials, not JSON data.
  • Server-Led Rendering: The responsibility for rendering data into HTML shifts from the client's browser back to the server.
  • Simplicity and Efficiency: This approach eliminates a significant amount of client-side JavaScript, reducing complexity and initial bundle size.

Now that you have mastered fetching and displaying data, you are fully equipped to build dynamic user interfaces. In our next lesson, we will begin Module 4, "Building CRUD Interfaces," by applying this pattern to implement the "Read" part of a CRUD feature: loading and displaying a list of items when a page first loads.

Can't find a good explanation? Sign up and we'll make it for you

Sign up