Skip to content

Using React In Your Qwik Application

This article was written over 18 months ago and may contain information that is out of date. Some content may be relevant but please refer to the relevant official documentation or available resources for the latest information.

Introduction

React, developed by Meta, is a JavaScript library for building user interfaces, and it is one of the most used UI JavaScript libraries in the world. React will be turning a decade old by May 2023. It has gained a lot of popularity over the years, and its latest version, React 18, was released in March 2022.

Qwik is a new JavaScript framework by Misko Hevery, creator of Angular, for building frontend browser applications. The major benefit of Qwik is its performance optimization, which features resumability and lazy loading.

As it stands now, there are virtually no Qwik third-party packages or libraries that currently exist, but luckily the Qwik team factored this in, making it easy for developers to easily integrate React libraries or your old React components into your Qwik project without too much difficulty.

In this article, I will show you how to easily integrate React libraries or components into your Qwik project.

Project Set Up

To get started, we need to create a new Qwik app. We can do this by running the following command in our terminal:

npm create qwik@latest

You can also get additional tools and configurations using our starter.dev kit by running the command in your terminal:

npm create @this-dot/starter --kit qwik-graphql-tailwind

You will be prompted to enter the name of your project (let’s call it qwik-react), choose the default option when asked to select a starter, and then install npm dependencies.

create qwik app

Now we have our Qwik application ready to go. Let’s start the development server and see what it looks like;

npm run dev
successful running app

Now that our app is up and running we will see how we can integrate a React package and component into our Qwik project.

Integrating React in Qwik

Like most JavaScript frontend libraries or frameworks, React makes use of hydration, which has its drawbacks and might be more expensive than you think. Qwik needs no hydration on load. It’s just pure HTML. This makes Qwik qwiker to load UIs, with which users can start interacting. You should keep this in mind when considering to include React components in your Qwik applications.

QwikReact is a tool that allows you to use React components in Qwik, including the whole ecosystem of component libraries such as Material UI, Threejs and React Spring. To get started, we need to run this command inside our Qwik app:

npm run qwik add react

This will install needed dependencies such as qwik-react, react, and react-dom. It will also add emotion and mui, which you can uninstall if you don’t intend to use them.

qwik react

If we check our project, we should now have some new folders generated. The most important is the src/integrations/react. This is where all our React components will be implemented or React packages will be used.

Qwikify$

The qwikify$ function is exported from @builder.io/qwik-react, which converts React components into Qwik components that you can use across your application, and allows Qwik to implement partial hydration of React components. You cannot use React components in Qwik without converting them first to remove React’s hydration pattern, which is not supported in Qwik, using qwikify$().

Another important thing to remember is to make sure the file containing your React component has this;

/** @jsxImportSource react */

This needs to be imported at the top of the file as this serves as instructions to the compiler to use React as the JSX factory. This means you cannot mix your React components with a Qwik component.

qwikify - 1

The code above is from the Qwik demo. You can see how the React components are wrapped with the qwikify$() function.

If your React package requires some configuration, don’t try to pass it as a props. Instead, do every configuration right inside the file, ensuring only the dynamic data is passed through.

qwikify - 2

The code above is from our Qwik GitHub showcase. Check out the full source code here.

So once you are done with Qwikifying your React component, you can now import and use it just as you would normally do a Qwik component.

importing qwik react component
rendering react component in qwik

Let’s run our application, and navigate to the React page at http://localhost:5173/react to view the default Qwik demo;

npm run dev
react table running successfully

Interactivity

Qwik tries to reduce or completely remove hydrations, but React heavily depends on it. This means we have to find a way to hydrate our React Component without affecting the concept of Qwik. Qwik allows you to decide when to hydrate your components by using the client: JSX properties. This technique is commonly referred to as “partial hydration”. For more information on this checkout Adding Interactivity on Qwik Docs.

Conclusion

In this article, we saw how to convert React to a Qwik component. We also learned about the dos and don’ts of using React in Qwik, as well as how to handle hydration. I hope you enjoyed this article. Thank you for reading!

If you have any questions or run into any trouble, feel free to join the discussions going on at starter.dev or on our Discord.

This Dot is a consultancy dedicated to guiding companies through their modernization and digital transformation journeys. Specializing in replatforming, modernizing, and launching new initiatives, we stand out by taking true ownership of your engineering projects.

We love helping teams with projects that have missed their deadlines or helping keep your strategic digital initiatives on course. Check out our case studies and our clients that trust us with their engineering.

You might also like

Unit Testing Qwik Components cover image

Unit Testing Qwik Components

Unit Testing Qwik Components Qwik is a new, superfast JavaScript framework from builder.io. Created by Miško Hevery, the author of AngularJS, Qwik aims to deliver instant loading web applications of any size or complexity through resumability. This is accomplished partially by delaying the execution and download of JavaScript for as long as possible while providing an excellent developer experience. > "You know React? You know Qwik." > — qwik.builder.io Given Miško's background as the creator of AngularJS, it's interesting that writing Qwik feels very similar to writing React. It even has a React compatibility mode. Personally, I have experience using mostly Angular, but I found that developing with Qwik was very smooth and enjoyable. So, although I am definitely hesitant to jump on new technologies, after attending Miško's workshop, browsing through all the resources at framework.dev tinkering with Qwik, and building a couple of apps with it, I became a fan. However, being a responsible software developer, I then wanted to add unit tests to my Qwik app. And because Qwik is relatively new, I found out there was little documentation on how to do this. Furthermore, until recently, there were no tools to easily set up and interact with Qwik components in unit tests. But that didn't stop me. I explored, asked, and waited for a PR to be merged, and now I am proud to present a comprehensive guide to unit testing Qwik apps. So, without further ado, let's dive into setting up our testing environment. Configuring a Testing Environment There are several options when it comes to choosing a testing framework, and I have even experimented with using Jest, as it is the popular choice for unit testing. However, since Qwik uses Vite, I found that using Vitest was the most straightforward and efficient option. Vitest is specifically designed to be the go-to test runner for Vite projects, which makes it a great fit. If you are familiar with Jest, you will be happy to know that the Vitest API is very similar, so you won't have to learn much to use it effectively. Before moving further to the actual setup, let's make sure you have a Qwik project to test. If you don't yet, you can simply create one by running npm create qwik@latest. Now, let's set up vitest in our Qwik project. It takes 3 easy steps: 1. Install Vitest as a dev dependency by running npm i vitest --save-dev from the root of your project. This will update the devDependencies array in your package.json file. 2. Update your vite.config.ts file to include a test configuration in the defineConfig function. You can start with an empty object for now, but you can always add configuration options later on. Your vite.config.ts should look something like this: ` 3. Update the "scripts" section of your package.json file to include commands for running vitest once, running it in watch mode, and for generating coverage reports. Your "scripts" section should look something like this: ` After completing these steps, you should be able to run npm run test and npm run coverage from your terminal to use Vitest. Note that if you run npm run test and you don't have any tests yet, which is likely the case at this point, you will see the message No test files found, exiting with code 1. Don't worry. We are about to add some tests shortly. Writing Tests By default, vitest will look for files with names that match the pattern '**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}. In a Qwik project that uses TypeScript and returns JSX elements, it makes sense to use the *.spec.tsx or *.test.tsx pattern. I prefer to use the.spec suffix. But .test works just as well, and is equally valid. Feel free to choose the one that you like best. To proceed with writing a unit test, we will need a component to test. For this example, we will use a simple counter component that has a div that displays a number and a button that increments it. To create the component, follow these steps: 1. Go to the src/components directory, and create a new folder called counter. 2. Inside the counter folder, create a new file called counter.tsx and add the following code: ` 3. Next to the counter.tsx file, create a new file called counter.spec.tsx file next to it. This file will contain the unit tests for the Counter component. Now that we have our component and our test file, we can proceed to write our unit tests. Let's open counter.spec.tsx and add some boilerplate along with a simple test to verify we have everything set up correctly: ` We have a describe method that groups related tests together (in our case, we're grouping all the tests we will write for our Counter component), an expect method which is used to make assertions about the values returned by the code being tested, and an it method that defines an individual test. If we now run npm run test, we should see the following output: ` Writing a Simple Test Case Now that we verified that our dummy test work, let's actually test our component's behavior. First, we want to test that it renders correctly, so we will remove our dummy test and leverage the new createDOM method from @builder.io/qwik.testing to render our Counter component inside the test: ` Rerunning the test should result in a pass if we did everything correctly. Now we know our component does render and displays zero as the count. Testing Interactions "Great," you say, "but I want to test the component's logic, not just the initial render!". Well, you're in luck because the createDOM method returns one more property - userEvent - that you can use to interact with the component's DOM. This allows us to simulate user interactions, such as clicking a button, and test whether the component responds correctly. For example, we can test whether our counter correctly increments the count by clicking the button. Here is the updated code example: ` With this additional test, we can be confident that our Counter component not only renders correctly, but also updates the count as expected when the increment button is clicked. Voilà, our component's behavior has been verified! Mocking Qwik Hooks So far, we have a test that verifies the component's logic, which is great! However, there may come a time when we need to mock parts of the component's logic to test certain scenarios. Unfortunately, here comes a little trade-off for the sake of Qwik's quickness. The component$ wrapper does not expose the internals of the component, so we cannot easily modify it for our tests. Fortunately, the most common thing we need to mock in Qwik components are hooks such as useLocation() or useStore(). We can do this by using vi.mock. As we can read in the Vitest docs, the vi.mock method takes two arguments: the path to the module that we want to mock, and a function that returns the mocked module. For example, if we want to modify the initial count in our useStore() hook to be _1_, we can mock the entire @builder.io/qwik module and return the actual module with the modified initial value. We can use the JavaScript bind method to do this. The call to vi.mock can be placed anywhere in the code as it is hoisted and will always be called before modules are imported, but for clarity, we will put it in a beforeAll block: ` Mocking the useLocation hook is even simpler, as it is not expected to change during a test. In this case, we can directly return an object from the mock. Here is an example of how to mock the useLocation hook: ` Conclusion As a newcomer to the world of JavaScript frameworks, Qwik offers a unique approach to building fast, efficient web applications. However, we shouldn't forget about the quality and robustness of our code. In this blog post, we provided a comprehensive guide on how to set up and write tests for your Qwik components. Setting up a testing environment for a Qwik app is relatively straightforward. Qwik uses Vite as its build tool, which means that the most efficient option for unit testing is to use Vitest, a test runner specifically designed for Vite projects. We showed how to install Vitest and update the Vite config file to include a test configuration, and went through examples of how to write tests for Qwik components, including how to mock hooks and test interactions with the DOM. By following the steps and examples in this post, you can easily add unit tests to your Qwik app, and ensure that your components are working correctly. This will give you confidence in your code, and allow you to build more complex and robust applications with Qwik. And if you found this article a bit overwhelming, do not worry, you can check out the Qwik starter kit which includes examples of already implemented tests. Have fun writing Qwik and reliable apps!...

How to Setup Storybook in a Qwik Project cover image

How to Setup Storybook in a Qwik Project

Introduction Storybook is a great tool for testing and visualizing your components in different states. In this article, we will see how to setup Storybook in a Qwik project. Qwik Qwik is a new JavaScript framework by Misko Hevery, creator of Angular, for building frontend browser applications. The major benefit of Qwik is its performance optimization, and this is achieved through zero loading, resumability, lazy loading, reduced rendering, scalability, and code once. For more information on Qwik, you can check out the docs, github repo, and discord. Project Set Up To get started, we need to create a new Qwik app. We can do this by running the following command in our terminal: ` Initialize Storybook Storybook, unfortunately, doesn’t have a Qwik template yet because it is a new Framework. So the work around is to use the html template . Using the command below, we can initialize Storybook: ` During the initialization, Storybook would ask to automatically install some optional dependencies such as; EslintPlugin and npm7, you can accept or reject it. To accept, type y and hit Enter to progress. Storybook would try to setup a default stories folder, which is based on the ` template we choose, which is `. It is not compatible with the Qwik compiler and will result in compilation errors, so we will have to delete it to avoid running into such errors. Project Structure Our project structure is already setup by Qwik, and Storybook initialization has created a .storybook folder. But we need to make some changes to the Storybook file extension since our project is in TypeScript. This is a snippet of the folders in our project: ` Configuring Storybook Since Qwik runs on Vite, we need to set up the viteFinal function in our main.ts file, which will give us the config that we will use to register our Qwik Vite plugin. Add this line of code in the configuration object: ` In the preview.ts file, this is where we configure how Storybook renders our stories. We need to execute Qwikloader. This will help in registering global browser events, and much more Qwik related benefits. We will replace the content in the file with the code below: ` This solution was found in this discussion: How to do component testing with Qwik?. I believe when the Qwik Storybook type template becomes available these configurations will be there by default. Now we are done with the configuration, let's run storybook and see what we have: ` Creating Stories We can create our first story, we will create a story for our Qwik app component. We will create this story for our default Qwik Header component. I modified the Header component to accept a menus props: ` Conclusion In this article, we saw how to setup Storybook in a Qwik project. We also saw how to create our first story. I hope you enjoyed this article. Thanks for reading. If you don't want to do these steps yourself, check out our starter.dev Qwik kit that already has Storybook enabled for your use here. A link to the project repo can be found here. If you have any questions or run into any trouble, feel free to reach out on Twitter....

Utilizing Browser Storage to Enhance User Experience in a Qwik Application cover image

Utilizing Browser Storage to Enhance User Experience in a Qwik Application

Introduction As front-end developers, we are always looking for ways to enhance the user experience of our applications. One of the ways we can achieve this is by utilizing the browser storage to store data, and implement some form of caching. Our web browser has provided us with different storage options to store data such as cookies, localStorage, and indexDB. In this article, we will be looking at how we can use storage to enhance a Qwik application. We are going to also explore hook technology in implementing this. Hooks 🪝 We will be extracting our storage function into a hook function that we can use in any part of our application. What are Hooks? Hooks are JavaScript functions that manage a component’s state and side effects by isolating them. That means we can isolate all the stateful logic into a hook and use it in any component. And just like in ReactJS, Qwik also allows us to create our own custom hooks. Project Set Up To get started, we need to create a new Qwik app. We can do this by running the following command in our terminal: ` You can also get additional tools and configurations using our starter.dev kit by running the command in your terminal: ` After the project is created, we can run the following command to start the development server: ` Now we can open our browser and navigate to http://localhost:5143 to see our app running. The demo app we will be building is a simple form with an input field and a button. The input field will be used to enter a value, and the button will be used to reset the form and the storage state. We will also see how we apply this functionality in our Qwik GitHub showcase app to persist/catch data we fetch from the GitHub API. Storage Hook After the project is created, we can create a new folder in the src folder and name it “hooks”. In the hooks folder, we will create a new file and name it useLocalStorage.ts. In this file, we will create our useLocalStorage hook. ` Let me explain what is happening here: - The useStore hook is used to store the value. We initially set this value to the initial state value passed to our custom hook. - In the useClientEffect$ hook, which runs on the client, we try to update our store value with the value from the localStorage based on the key passed to the hook. If the value is found, we set its parsed value to the store value. If not, we set the store value to the initial state passed to the hook. We also catch any error that might occur, and set the store value to the initial state. - We also have a setValue$ function that is used to set the value of the store and also save it to the localStorage. The setValue$ function is wrapped in a $ function, which is used to create a QRL function- a Qwik optimizer marker function. For more information on QRL, visit the docs. - We also return store and the setValue$ function. This exposes them to be consumed in our components. We don't want to return the value of the store or else it will lose its reactivity. Form Component In the components folder, we will create a new folder called form, which will contain an index file that will export our Form component. The form will be expecting two props; value and setValue, which are from the useLocalStorage hook. ` In our index file, we will import the useLocalStorage hook and the Form component, and our updated index file will look like this: ` We can now see what our simple app looks like in the browser, and we can interact with it. By entering a value in the input field and reloading the page, we can see that the value persists. Next, we want to implement this hook in our Qwik GitHub showcase app to persist the gists data we fetch from the GitHub API and persisting it in the localStorage. We transform our fetch gists logic from this: ` to this; ` So we check if we have cached gists in the Storage. If we do, we set the store data to the cached gists. If not, we fetch the gists from the GitHub API and update the store data with the response. We also pass the setGists function to the updateGists function, which is the setValue$ function from the useLocalStorage hook. This function is used to set the value of the store, and also save it to the localStorage. Conclusion In this article, we were able to understand why we need to improve user experience with a focus on persisting data. We also saw how to create a hook in a Qwik framework, and use our hook to persist data in the localStorage. A link to the project repo can be found here and for our Qwik starter.dev showcase app, here. If you have any questions or run into any trouble, feel free to reach out on Twitter or on our Discord....

Implementing Dynamic Types in Docusign Extension Apps cover image

Implementing Dynamic Types in Docusign Extension Apps

Implementing Dynamic Types in Docusign Extension Apps In our previous blog post about Docusign Extension Apps, Advanced Authentication and Onboarding Workflows with Docusign Extension Apps, we touched on how you can extend the OAuth 2 flow to build a more powerful onboarding flow for your Extension Apps. In this blog post, we will continue explaining more advanced patterns in developing Extension Apps. For that reason, we assume at least basic familiarity with how Extension Apps work and ideally some experience developing them. To give a brief recap, Docusign Extension Apps are a powerful way to embed custom logic into Docusign agreement workflows. These apps are lightweight services, typically cloud-hosted, that integrate at specific workflow extension points to perform custom actions, such as data validation, participant input collection, or interaction with third-party services. Each Extension App is configured using a manifest file. This manifest defines metadata such as the app's author, support links, and the list of extension points it uses (these are the locations in the workflow where your app's logic will be executed). The extension points that are relevant for us in the context of this blog post are GetTypeNames and GetTypeDefinitions. These are used by Docusign to retrieve the types supported by the Extension App and their definitions, and to show them in the Maestro UI. In most apps, these types are static and rarely change. However, they don't have to be. They can also be dynamic and change based on certain configurations in the target system that the Extension App is integrating with, or based on the user role assigned to the Maestro administrator on the target system. Static vs. Dynamic Types To explain the difference between static and dynamic types, we'll use the example from our previous blog post, where we integrated with an imaginary task management system called TaskVibe. In the example, our Extension App enabled agreement workflows to communicate with TaskVibe, allowing tasks to be read, created, and updated. Our first approach to implementing the GetTypeNames and GetTypeDefinitions endpoints for the TaskVibe Extension App might look like the following. The GetTypeNames endpoint returns a single record named task: ` Given the type name task, the GetTypeDefinitions endpoint would return the following definition for that type: ` As noted in the Docusign documentation, this endpoint must return a Concerto schema representing the type. For clarity, we've omitted most of the Concerto-specific properties. The above declaration states that we have a task type, and this type has properties that correspond to task fields in TaskVibe, such as record ID, title, description, assignee, and so on. The type definition and its properties, as described above, are static and they never change. A TaskVibe task will always have the same properties, and these are essentially set in stone. Now, imagine a scenario where TaskVibe supports custom properties that are also project-dependent. One project in TaskVibe might follow a typical agile workflow with sprints, and the project manager might want a "Sprint" field in every task within that project. Another project might use a Kanban workflow, where the project manager wants a status field with values like "Backlog," "ToDo," and so on. With static types, we would need to return every possible field from any project as part of the GetTypeDefinitions response, and this introduces new challenges. For example, we might be dealing with hundreds of custom field types, and showing them in the Maestro UI might be too overwhelming for the Maestro administrator. Or we might be returning fields that are simply not usable by the Maestro administrator because they relate to projects the administrator doesn't have access to in TaskVibe. With dynamic types, however, we can support this level of customization. Implementing Dynamic Types When Docusign sends a request to the GetTypeNames endpoint and the types are dynamic, the Extension App has a bit more work than before. As we've mentioned earlier, we can no longer return a generic task type. Instead, we need to look into each of the TaskVibe projects the user has access to, and return the tasks as they are represented under each project, with all the custom fields. (Determining access can usually be done by making a query to a user information endpoint on the target system using the same OAuth 2 token used for other calls.) Once we find the task definitions on TaskVibe, we then need to return them in the response of GetTypeNames, where each type corresponds to a task for the given project. This is a big difference from static types, where we would only return a single, generic task. For example: ` The key point here is that we are now returning one type per task in a TaskVibe project. You can think of this as having a separate class for each type of task, in object-oriented lingo. The type name can be any string you choose, but it needs to be unique in the list, and it needs to contain the minimum information necessary to be able to distinguish it from other task definitions in the list. In our case, we've decided to form the ID by concatenating the string "task_" with the ID of the project on TaskVibe. The implementation of the GetTypeDefinitions endpoint needs to: 1. Extract the project ID from the requested type name. 1. Using the project ID, retrieve the task definition from TaskVibe for that project. This definition specifies which fields are present on the project's tasks, including all custom fields. 1. Once the fields are retrieved, map them to the properties of the Concerto schema. The resulting JSON could look like this (again, many of the Concerto properties have been omitted for clarity): ` Now, type definitions are fully dynamic and project-dependent. Caching of Type Definitions on Docusign Docusign maintains a cache of type definitions after an initial connection. This means that changes made to your integration (particularly when using dynamic types) might not be immediately visible in the Maestro UI. To ensure users see the latest data, it's useful to inform them that they may need to refresh their Docusign connection in the App Center UI if new fields are added to their integrated system (like TaskVibe). As an example, a newly added custom field on a TaskVibe project wouldn't be reflected until this refresh occurs. Conclusion In this blog post, we've explored how to leverage dynamic types within Docusign Extension Apps to create more flexible integrations with external systems. While static types offer simplicity, they can be constraining when working with external systems that offer a high level of customization. We hope that this blog post provides you with some ideas on how you can tackle similar problems in your Extension Apps....

Let's innovate together!

We're ready to be your trusted technical partners in your digital innovation journey.

Whether it's modernization or custom software solutions, our team of experts can guide you through best practices and how to build scalable, performant software that lasts.

Prefer email? hi@thisdot.co