Build an efficient app with Qwik React
Tags: react, webdev
Published: 2023-08-01 13:29:43

**Written by [David Omotayo](https://blog.logrocket.com/author/davidomotayo/)✏️**

[Qwik](https://qwik.builder.io) is a cutting-edge JavaScript framework that revolutionizes the concept of reactive UI and significantly improves web page loading performance, regardless of site complexity. The primary premise of the framework is to serve HTML with minimal JavaScript, only increasing interaction incrementally as needed. This method, known as resumability, is thought to be superior to hydration. 

Qwik offers several benefits for web application development, but its ecosystem is still in its infancy and the framework is not yet extensively used. In this tutorial, we'll explore how to use the Qwik React package, which is in beta as of this writing, to integrate Qwik with React. We’ll also look at how to use Qwik components, referred to as “islands”, with native React components. 

_Jump ahead:_

*   [Prerequisites](#prerequisites)
*   [What is Qwik React?](#what-is-qwik-react)
*   [Getting started](#getting-started)
*   [Understanding the project structure](#understanding-project-structure)
*   [Using the `qwikify$()` function](#using-qwikify-function)
*   [Hydrating components](#hydrating-components)
    *   [Partial hydration with the `eagerness` property](#partial-hydration-eagerness-property)
    *   [Partial hydration with the `client:` property](#partial-hydration-client-property)
*   [Achieving interactivity without hydration](#achieving-interactivity-without-hydration)
*   [Understanding inter-component communication](#understanding-inter-component-communication)
*   [Integrating React libraries](#integrating-react-libraries)
*   [Limitations of Qwik React](#limitations-qwik-react)
    *   [Components are isolated](#components-isolated)
    *   [`qwikify$()` is not so quick](#qwikify-not-quick)

## Prerequisites

To follow along with this tutorial, you should have the following:

*   Working knowledge of Typescript and React
*   Node.js installed on your machine
*   A code editor, preferably VS Code

## What is Qwik React?

The [Qwik React](https://qwik.builder.io/docs/integrations/react/) package is a unique combination of Qwik components with React designed to produce highly efficient applications. Given their varied performance and internal architecture, you might ask why anyone would want to combine Qwik and React. 

Well, incorporating React components into a Qwik application can be helpful for a number of reasons, particularly in terms of performance and time-to-interactivity. However, there are some advantages that React brings to the table compared to Qwik, such as community. 

The React ecosystem has grown significantly in recent years, establishing itself as one of the [largest web development communities on the internet](https://survey.stackoverflow.co/2023/#web-frameworks-and-technologies). Consequently, there is an abundance of tools and libraries developed by the community specifically for React, which improves the process of creating web applications with this framework. While the Qwik community is still growing, there are currently a limited number of tools and libraries available that can compete with or divert attention away from React. 

In an effort to leverage the extensive React ecosystem and the wide range of readily available tools and libraries, the Qwik team devised the "Qwik React" solution. This approach involves converting React components into Qwik components, also known as islands. By doing so, we can harness the power of React's vast ecosystem, which includes popular libraries such as [MUI](https://mui.com), [ThreeJs](https://threejs.org), and [React Spring](https://www.react-spring.dev), to enhance our applications.

## Getting started

Before we dive into the technical aspect of Qwik React and its benefits, we’ll need to create and configure a Qwik development environment. 

If you don’t already have a Qwik application, you can quickly set one up by following these steps: 


Step 1: Open your terminal and run the below commands to bootstrap a Qwik project, install the dependencies, and start the development server:

```bash
npm create qwik@latest
cd qwik-app
npm start
```

After running the command, the CLI will guide you through an interactive menu to set up the app according to your preference. You can use the options shown in the screenshot below as a guide. ![Setting Up New Qwik Project](http://blog.logrocket.com/wp-content/uploads/2023/07/setting-up-new-qwik-project.png) 

Step 2: Once your project is set up and ready, install Qwik React and the required dependencies for the project by running the following command:

```bash
npm run qwik add react
```

This code will install react, react-dom, and other required packages. It will also create a `demo` and `react` route for showcasing the React integration at `http://localhost:5173/react/` and `http://localhost:5173/demo/`. Additionally, it will create an `integration` folder where React components will be stored in our project: ![Adding React To Qwik Project](http://blog.logrocket.com/wp-content/uploads/2023/07/adding-react-to-qwik-project.png) ![Adding Required Packages Qwik React App](http://blog.logrocket.com/wp-content/uploads/2023/07/adding-required-packages-qwik-react-app.png) 

We’ll talk more about the `integration` folder later in this article. 

Step 3: Next, configure Vite to use the `qwik-react` plugin. You can do this by navigating to the `vite.config.ts` file and adding the following code:

```typescript
import { qwikReact } from '@builder.io/qwik-react/vite';

export default defineConfig(() => {
   return {
     ...,
     plugins: [
       ...,
       // The important part
       qwikReact()
     ],
   };
});
```

We’re all set. Now we can start using the package to convert React components into Qwik islands.

## Understanding the project structure <a name="understanding-project-structure">

Once you’ve completed the project setup and successfully integrated Qwik React, you’ll notice that the structure of your project becomes slightly more complex than its initial state, especially if you are still getting accustomed to Qwik's project structure. 

As mentioned previously, the Qwik React package adds two new folders, `routes` and `integration`, to a project upon installation. The `routes` folder automatically generates a route for each file added within it, while the `integration` folder stores and isolates React components. This separation is necessary because it's bad practice to place Qwik and Qwik React components in the same directory. 

By default, the `routes` folder contains two routes, `react` and `demo`. Within the `demo` route, there are two nested routes:, `flower` and `todolist`. 

We can access these routes in our browser by navigating to either the `demo/flower` or `demo/todolist` address: ![Qwik React Demo Route](http://blog.logrocket.com/wp-content/uploads/2023/07/qwik-react-demo-route.gif) 

The `react` route has just one route that renders a number of islands from the `mui.tsx` React component within the `integration` folder: ![React Component Integration Folder Qwik React](http://blog.logrocket.com/wp-content/uploads/2023/07/react-component-integration-folder-qwik-react.png) This component houses three MUI components: `Button`, `Slider`, and `TableApp` components that are being wrapped with a `qwikify$()` function and exported:

```javascript
/** @jsxImportSource react */
import { qwikify$ } from "@builder.io/qwik-react";
import { Button, Slider } from "@mui/material";
import { DataGrid, GridColDef, GridValueGetterParams } from "@mui/x-data-grid";
export const MUIButton = qwikify$(Button);
export const MUISlider = qwikify$(Slider, { eagerness: "hover" });
export const TableApp = qwikify$(() => {
  const columns: GridColDef[] = [
    { field: "id", headerName: "ID", width: 70 },
    { field: "firstName", headerName: "First name", width: 130 },
    { field: "lastName", headerName: "Last name", width: 130 },
    {
      field: "age",
      headerName: "Age",
      type: "number",
      width: 90,
    },
    {
      field: "fullName",
      headerName: "Full name",
      description: "This column has a value getter and is not sortable.",
      sortable: false,
      width: 160,
      valueGetter: (params: GridValueGetterParams) =>
        `${params.row.firstName || ""} ${params.row.lastName || ""}`,
    },
  ];
  const rows = [
    { id: 1, lastName: "Snow", firstName: "Jon", age: 35 },
    { id: 2, lastName: "Lannister", firstName: "Cersei", age: 42 },
    { id: 3, lastName: "Lannister", firstName: "Jaime", age: 45 },
    { id: 4, lastName: "Stark", firstName: "Arya", age: 16 },
    { id: 5, lastName: "Targaryen", firstName: "Daenerys", age: null },
    { id: 6, lastName: "Melisandre", firstName: null, age: 150 },
    { id: 7, lastName: "Clifford", firstName: "Ferrara", age: 44 },
    { id: 8, lastName: "Frances", firstName: "Rossini", age: 36 },
    { id: 9, lastName: "Roxie", firstName: "Harvey", age: 65 },
  ];
  return (
    <>
      <h1>Hello from React</h1>
      <div style={{ height: 400, width: "100%" }}>
        <DataGrid
          rows={rows}
          columns={columns}
          // @ts-ignore
          pageSize={5}
          rowsPerPageOptions={[5]}
          checkboxSelection
          disableSelectionOnClick
        />
      </div>
    </>
  );
});
```

## Using the `qwikify$()` function <a name="using-qwikify-function">

`qwikify$()` is a handy utility function in Qwik React that lets you turn React components into Qwik islands that you can reuse throughout your application. The `@builder.io/qwik-react` package exports the function, and it works by wrapping an existing React component, transforming it into a Qwik component. This way, you can customize the components and control when they get hydrated, making your app significantly faster. 

Here’s a simple example of how to use the `qwikify$()` function:

```typescript
///integrations/react/dropdown.tsx

/** @jsxImportSource react */

import { qwikify$ } from "@builder.io/qwik-react";
import { Select, MenuItem} from "@mui/material";

export const Dropdown = qwikify$(
  ({ value, onChange } : { value: string; onChange: Function }
) => {
    return (
      <div className="dropdown">
        <Select
          value={value}
          onChange={(e) => onChange(e)}
          sx={{
            width: 250,
            height: 50,
            backgroundColor: "gray",
            border: "solid 2px white",
            color: "white",
          }}
        >
          <MenuItem value={"Rice"}>Rice</MenuItem>
          <MenuItem value={"Beef"}>Beef</MenuItem>
          <MenuItem value={"Pizza"}>Pizza</MenuItem>
          <MenuItem value={"Milk"}>Milk</MenuItem>
          <MenuItem value={"Sausage"}>Sausage</MenuItem>
        </Select>
      </div>
    );
  }
);
```

Here, we created a `dropdown` component in the integration folder, used MUI’s `Select` and `MenuItem` components to build a dropdown, and then exported the component as an island using the `qwikify$()` function. 

_**N.B.,** the`/** @jsxImportSource react */` import at the top of the code enables us to< tell the compiler to use React as the default JSX factory; it is required at the top level of every Qwik React component_ 

Now that the component is wrapped with the `qwikify$()` function, we can use it as a Qwik component in a Qwik route like the `react` route:

```typescript
import { component$, useSignal } from "@builder.io/qwik";
import type { DocumentHead } from "@builder.io/qwik-city";
import { Dropdown } from "~/integrations/react/example";

export default component$(() => {
  const food = useSignal<"Rice" | "Beef" | "Pizza" | "Milk" | "Sausage">(
    "Rice"
  );

  return (
    <>
      <Dropdown
        value={food.value}
        onChange$={(e: any) => {
          food.value = e.target.value;
        }}
      />
    </>
  );
});

export const head: DocumentHead = {
  title: "Qwik React",
};
```

![React Component Wrapped In Qwikify Function](http://blog.logrocket.com/wp-content/uploads/2023/07/react-component-wrapped-in-qwikify-function.gif) Notice that code in the below snippet is being wrapped with the `component$` utility function:

```typescript
export default component$(() => {
...

});
```

The reason for the wrapping is that this component is a Qwik component. Unlike the files in the `integration` folder, all the files in the `route` folder are Qwik components.

## Hydrating components

The `qwikify$()` utility function converts React components into plain simple HTML that only runs on the server. This means that the components are not interactive by default when rendered. 

For example, the dropdown that we created earlier is not interactive when clicked. This is because React is not loaded yet and the component is running on the server as plain HTML, meaning the component hasn’t been hydrated yet: ![Qwik React Component Not Hydrated Not Interactive](http://blog.logrocket.com/wp-content/uploads/2023/07/qwik-react-component-not-hydrated-not-interactive.gif) 

We have two options to make the component interactive. We can use Qwik signals and the `host:` listener to make the component interactive as a server-side component. Alternatively, we can load React on the client side and hydrate the component based on certain conditions using the `eagerness` property on the `qwikify$()` function.

### Partial hydration with the `eagerness` property <a name="partial-hydration-eagerness-property">

One of the quirks of building an application with React is the hydration task that unconditionally happens at load time, adding a massive overhead and making the app slower. Qwik lets us mitigate this problem by only partially hydrating the application, thereby boosting performance. 

We can use the `qwikify$()` function to achieve partial hydration in our Qwik React components. This function takes a second object argument that can have an `eagerness` property with values that can be used to hydrate components based on certain conditions like `load`, `hover`, `idle`, or `visible`. 

To make our dropdown component interactive, we can add the `eagerness` property to the `qwikify$()` function, like so:

```typescript
export const Dropdown = qwikify$(
  ({ value, onChange}:{value: string, onChange: Function}) => {
    return (
      <div className="dropdown">
        <Select
          value={value}
          onChange={(e) => onChange(e)}
          sx={{
            width: 250,
            height: 50,
            backgroundColor: "gray",
            border: "solid 2px white",
            color: "white",
          }}
        >
          <MenuItem value={"Rice"}>Rice</MenuItem>
          <MenuItem value={"Beef"}>Beef</MenuItem>
          <MenuItem value={"Pizza"}>Pizza</MenuItem>
          <MenuItem value={"Milk"}>Milk</MenuItem>
          <MenuItem value={"Sausage"}>Sausage</MenuItem>
        </Select>
      </div>
    );
  },
  { eagerness: "hover" }
);
```

Now the component will become interactive when our cursor hovers over it: ![Qwik React Component Partial Hydration Eagerness Property](http://blog.logrocket.com/wp-content/uploads/2023/07/qwik-react-component-partial-hydration-eagerness-property.gif)

### Partial hydration with the `client:` property <a name="partial-hydration-client-property">

Another method to partially hydrate Qwik React components is to use the `client:` JSX property with the following conditions:

*   `visible`: the component hydrates when it becomes visible on the viewport
*   `load`: the component eagerly hydrates when the DOM loads
*   `idle`: the component eagerly hydrates when the browser becomes idle
*   `hover`: the component eagerly hydrates when the user mouses over it
*   `signal`: the component hydrates whenever the assigned signal becomes `true`
*   `event`: the component eagerly hydrates when specified events are fired
*   `only`: the component will only run on the client side

These conditions can be prefixed to the `client:` property (for example, `client:visible`) and assigned to the component to be partially hydrated. 

The `client:` property is similar to the `eagerness` property on the `qwikify$()` function, except it offers more hydration conditions. 

Here's an example of how we can use the `client:` property on our dropdown component:

```typescript
export default component$(() => {
  const food = useSignal<"Rice" | "Beef" | "Pizza" | "Milk" | "Sausage">(
    "Rice"
  );

  return (
    <>
      <Dropdown
        client:hover
        value={food.value}
        onChange$={(e: any) => {
          food.value = e.target.value;
        }}
      />
    </>
  );
});
```

By eagerly hydrating React components, we gain a performance boost since React is only loaded for the component being hydrated, rather than the entire application. However, this approach contradicts the purpose of converting the component into an island in the first place.

## Achieving interactivity without hydration

With the `host:` listener, we don't have to hydrate an entire component just to make handlers, such as `onClick`, functional. Instead, we can make them functional on the server without the need to download React on the client side. 

To use the `host:` listener, simply replace React's `onClick` handler with Qwik's `onClick$` handler and add the `host:` prefix to it, as demonstrated below:

```typescript
export default component$(() => {
...

  return (
    <div>
        ...
      <MUIButton
        host:onClick$={() => alert("Working without hydration")}
        variant="contained"
      >
        click
      </MUIButton>
    </div>
  );
});
```

Now, the component will be interactive without hydration, and if you go to the dev tool, you'll also see that no React code was downloaded: ![Qwik React Component Interactivity Without Hydration](http://blog.logrocket.com/wp-content/uploads/2023/07/qwik-react-component-interactivity-without-hydration.gif) The only drawback to using the `host:` listener is that we can only use it in a native Qwik component like the `react` route, where our components are being rendered. The `host:onClick$` handler is assigned to the `MUIButton` component in the `react` route, rather than the `integration/react/dropdown` directory, as shown in the code example above.

## Understanding inter-component communication <a name="understanding-inter-component-communication">

As your application grows, inter-component (or inter-island) communication becomes crucial. Particularly during this growth phase, it’s essential to understand the behavior of these components. 

By now, you're likely aware that selectively hydrating components is the optimal approach, avoiding unnecessary hydration of static or non-interactive components. However, dynamic components whose props are connected to an interactive component will get hydrated when their prop changes. 

The example below shows how inter-component communications work in Qwik React:

```typescript
//react/index.tsx

import { Display, Dropdown } from "~/integrations/react/example";

export default component$(() => {
  const food = useSignal<"Rice" | "Beef" | "Pizza" | "Milk" | "Sausage">(
    "Rice"
  );

  return (
    <div>
      <Dropdown
        value={food.value}
        onChange$={(e: any) => {
          food.value = e.target.value;
        }}
      />
      <Display food={food.value} />
    </div>
  );
});
export const Dropdown = qwikify$(
  ({ value, onChange }: { value: string; onChange: Function }) => {
    return (
      <div className="dropdown">
        <Select
          value={value}
          onChange={(e) => onChange(e)}
          sx={{
            width: 250,
            height: 50,
            backgroundColor: "gray",
            border: "solid 2px white",
            color: "white",
          }}
        >
          <MenuItem value={"Rice"}>Rice</MenuItem>
          <MenuItem value={"Beef"}>Beef</MenuItem>
          <MenuItem value={"Pizza"}>Pizza</MenuItem>
          <MenuItem value={"Milk"}>Milk</MenuItem>
          <MenuItem value={"Sausage"}>Sausage</MenuItem>
        </Select>
      </div>
    );
  },
  { eagerness: "hover" }
);

export const Display = qwikify$(({ food }:{food: string}
) => {
  return (
    <div style={{ marginLeft: "250px", fontSize: "27px" }}>
      {" "}
      Food Value:{" "}
      <span
        style={{
          backgroundColor: "white",
          color: "black",
          padding: "5px",
          borderRadius: "5px",
        }}
      >
        {food}
      </span>
    </div>
  );
});
```

Here, we created a `Display` component that shows the current value of the `food` signal, which is derived from the selected menu item on the dropdown component. When a food item on the dropdown is clicked, the `Display` component is automatically hydrated as soon as its prop changes: ![Qwik React Inter-Component Communication](http://blog.logrocket.com/wp-content/uploads/2023/07/qwik-react-inter-component-communication.gif)

## Integrating React libraries

The Qwik React package installs two React libraries by default: `emotion` and `Material UI`. One of the primary benefits of using Qwik React is that we can install and integrate any React library into our project and use it just like we would in a React application. 

For instance, if you wish to install a library such as React Query into your project, you can conveniently install it via the terminal using the following command:

```bash
npm i react-query
```

Then, under the `integration` folder, create a file and give it a name. Next, add your component logic, and wrap it in the `qwikify$()` method as follows:

```typescript
/** @jsxImportSource react */

import { qwikify$ } from "@builder.io/qwik-react";

import {
  useQuery,
  QueryClient,
  QueryClientProvider,
} from "react-query";

const TodoList = () => {
  const getTodos = async () => {
    const res = await fetch("https://jsonplaceholder.typicode.com/todos");
    return res.json();
  };

  const { data } = useQuery("todos", getTodos);

  return (
    <div className="todo">
      {data &&
        data.map((t: any) => {
          return (
            <div key={t.id} className="todo__items">
              <p>{t.title}</p>
            </div>
          );
        })}
    </div>
  );
};

export const Todo = qwikify$(
  () => {
    const queryClient = new QueryClient();
    return (
      <QueryClientProvider client={queryClient}>
        <TodoList />
      </QueryClientProvider>
    );
  },
  { eagerness: "visible" }
);
```

You can now use React query in your application to display the data that was fetched in any of the routes.  

```typescript
//react/index.tsx

import { component$, useSignal } from "@builder.io/qwik";
import { Todo } from "~/integrations/react/animate";

export default component$(() => {

  return (
    <div>
      <h2 class="title">Todos Lists</h2>
      <Todo />
    </div>
  );
});
```

![Qwik React Integrating React Libraries](http://blog.logrocket.com/wp-content/uploads/2023/07/qwik-react-integrating-react-libraries.gif)

## Limitations of Qwik React <a name="limitations-qwik-react">

Before opting to use Qwik React, there are a few constraints to consider. As of this writing, the package is still in beta; therefore, it’s not recommended for use in production. Right now, Qwik React is only a migration option for you to move your applications to Qwik. Let’s look at a couple of other limitations.

### Components are isolated <a name="components-isolated">

Every instance of a qwikified component is a separate React application, with its own set of states, style, context, and ability to be hydrated independently. 

Consider the dropdown component we created earlier. Let’s render multiple instances of the `Dropdown` in the `react` route, like this:

```typescript
export default component$(() => {
  const food = useSignal<"Rice" | "Beef" | "Pizza" | "Milk" | "Sausage">(
    "Rice"
  );

  return (
    <div>
      <Dropdown
        value={food.value}
        onChange$={(e: any) => {
          food.value = e.target.value;
        }}
      />

      <Dropdown
        value={food.value}
        onChange$={(e: any) => {
          food.value = e.target.value;
        }}
      />

      <Dropdown
        value={food.value}
        onChange$={(e: any) => {
          food.value = e.target.value;
        }}
      />
    </div>
  );
});
```

Here, each `Dropdown` will function as a separate self-contained React application. This means that they will each have their own state, lifecycle methods, and other React features that are independent of one another. Changes or alterations to the state of one `dropdown` instance will have no effect on the state of other instances.

### `qwikify$()` is not so quick <a name="qwikify-not-quick">

It's easy to abuse the `qwikify$()` function when using it to wrap components, leading to a loss in performance gains for your application. 

Consider a situation where multiple MUI components are needed to build a form. The common approach is to wrap each MUI component in a `qwikify$()` function and export them, like so:

```typescript
/** @jsxImportSource react */

import { qwikify$ } from "@builder.io/qwik-react";
import {
  Select,
  MenuItem,
  FormControl,
  FormLabel,
  TextField,
  FormGroup,
  Checkbox,
} from "@mui/material";

export const MUICheckbox = qwikify$(Checkbox);
export const MUIFormGroup = qwikify$(FormGroup);
export const MUITextField = qwikify$(TextField);
export const MUIFormLabel = qwikify$(FormLabel);
export const MUIFormControl = qwikify$(FormControl);
export const MUIMenuItem = qwikify$(MenuItem);
export const MUISelect = qwikify$(Select);
```

Adopting such an approach is detrimental because it reduces the performance of the application, and since every instance is independent, it results in duplicated styles and isolated contexts, and makes theming impossible. 

The optimal approach is to construct the entire form as a single qwikified React component and export it as a unified entity:

```typescript
/** @jsxImportSource react */

import { qwikify$ } from "@builder.io/qwik-react";
import {
  Select,
  MenuItem,
  FormLabel,
  TextField,
  FormGroup,
  Checkbox,
  Button,
} from "@mui/material";

export const Form = qwikify$(() => {
  return (
    <div>
      <form>
        <FormLabel>Enter Firstname</FormLabel>
        <TextField />
        <br />
        <FormLabel>Enter Lastname</FormLabel>
        <TextField />
        <br />
        <FormGroup>
          <Checkbox />
          <Checkbox />
          <Checkbox />
        </FormGroup>
        <br />
        <Select>
          <MenuItem>1</MenuItem>
          <MenuItem>2</MenuItem>
          <MenuItem>3</MenuItem>
          <MenuItem>4</MenuItem>
          <MenuItem>5</MenuItem>
        </Select>
        <br />
        <Button>submit</Button>
      </form>
    </div>
  );
});
```

## Conclusion

Qwik React offers an intriguing solution for converting React components to Qwik islands. However, it is not a "silver bullet"; you will eventually need to migrate your applications to Qwik.

This introduction to the Qwik React package aims to supply you with the fundamental knowledge to build applications that take advantage of the benefits of both ecosystems: Qwik and React. Refer to the documentation to learn more about the Qwik React package and how you can leverage what you’ve already built to create complex functionalities.

---

## Get set up with LogRocket's modern React error tracking in minutes:

1.Visit https://logrocket.com/signup/ to get an app ID.
2.Install LogRocket via NPM or script tag. `LogRocket.init()` must be called client-side, not server-side.

NPM:
```bash
$ npm i --save logrocket 

// Code:

import LogRocket from 'logrocket'; 
LogRocket.init('app/id');
```
Script Tag:
```javascript
Add to your HTML:

<script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script>
<script>window.LogRocket && window.LogRocket.init('app/id');</script>
```

3.(Optional) Install plugins for deeper integrations with your stack:
*   Redux middleware
*   ngrx middleware
*   Vuex plugin

[Get started now](https://lp.logrocket.com/blg/signup)