How to integrate LiFi Widget on your NextJS app
Published: 2024-05-20 01:24:59

Imagine seamlessly integrating the power of LIFI, a cutting-edge multi-chain liquidity aggregation protocol, is added to your Next.js application. LIFI facilitates any-to-any swaps by consolidating bridges and decentralized exchange (DEX) aggregators across over 20 networks. In this article, we'll explore the process of integrating the LIFI protocol into your Next.js app, unlocking a world of possibilities for frictionless cryptocurrency trading and enhanced liquidity management.

## Introduction
**Introducing LIFI:**
LIFI is a multi-chain liquidity aggregation protocol that supports any-2-any swaps by aggregating bridges and DEX aggregators across +20 networks. You can see it as a super-intelligent system that gathers all the places where people exchange money, like bringing together all the shops in a big marketplace. It helps people trade their money from one type to another, making it easy to switch between different currencies. So, instead of going to many other shops, LIFI brings them all to one place, making it simple and convenient for people to exchange money.

**LIFI Widget:**
The LIFI Widget comprises ready-made user interface elements seamlessly incorporating a secure cross-chain bridging and swapping feature into your web application. These components can be customized to align perfectly with your app's design, enhancing its visual appeal. By integrating the LIFI Widget, you can bolster your multi-chain strategy and draw in users from various locations, providing a user-friendly and secure experience.

## Let’s build our app together
**Setting up your Next.js app:**
You can begin setting up your NextJS application using these guidelines:

**_Installation:_** Start by installing Next.js using npm or yarn. Run the following command in your terminal:

```
npx create-next-app@latest
```

**_Project Structure:_** Next.js follows a convention-based file structure. Familiarize yourself with the default project structure, including pages, public, and style directories.
Here's how your folder structure would look like after installation of NextJS:



![Folder structure](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w04gwjomfi8i8e18372z.png)

We have successfully set up NextJS for our integration.

**Installing libraries**
We have to install LIFI libraries in our NextJS app to access its functionality in our web app. Use npm or yarn to install the LIFI Widget library. Run the following command in your terminal:

```
npm install --save @LIFI/widget
```

Or for those who use Yarn,

```
yarn add @LIFI/widget
```

This command will install the LIFI Widget package as a dependency on your project.



![package.json file](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2zdrk1a1e3cjlmq933sc.png)

By installing the LIFI Widget library, you'll gain access to pre-built UI components and functionality that enable secure cross-chain bridging and swapping within your Next.js application. This installation process sets the stage for integrating LIFI's powerful features seamlessly into your project.

**Integrating the Widget**
Create a new folder named components in your `/app` directory. After which we'll create our widget component named `Widget.tsx` and paste this code there:

```
'use client';

import type { WidgetConfig } from '@LIFI/widget';
import { LIFIWidget, WidgetSkeleton } from '@LIFI/widget';
import { ClientOnly } from './ClientOnly';

export function Widget() {
  const config = {
    appearance: 'light',
    theme: {
      container: {
        boxShadow: '0px 8px 32px rgba(0, 0, 0, 0.08)',
        borderRadius: '16px',
      },
    },
  } as Partial<WidgetConfig>;

  return (
    <main>
      <ClientOnly fallback={<WidgetSkeleton config={config} />}>
        <LIFIWidget config={config} integrator="nextjs-example" />
      </ClientOnly>
    </main>
  );
}
```

I am sure you're wondering why we have other components imported into our Widget component now; here is why: in modern web development, ensuring a smooth user experience is paramount. The ClientOnly Component serves a crucial role by selectively rendering content only after client-side JavaScript has fully loaded.

So, on that note, let's create a new component named `ClientOnly.tsx`

```
import { type PropsWithChildren } from 'react';
import { useHydrated } from '../hooks/useHydrated';

interface ClientOnlyProps extends PropsWithChildren {
  fallback?: React.ReactNode;
}

/**
 * Render the children only after the JS has loaded client-side. Use an optional
 * fallback component if the JS is not yet loaded.
 */
export function ClientOnly({ children, fallback = null }: ClientOnlyProps) {
  const hydrated = useHydrated();
  return hydrated ? children : fallback;
}

```

We also have the WidgetEvents.tsx component that offers real-time monitoring of asset transfers. It tracks key execution stages and potential errors, ensuring a smooth user experience.
Let's create our `WidgetEvents.tsx` component

```
'use client';
import type { Route } from '@LIFI/sdk';
import type {
  RouteExecutionUpdate,
  RouteHighValueLossUpdate,
} from '@LIFI/widget';
import { WidgetEvent, useWidgetEvents } from '@LIFI/widget';
import { useEffect } from 'react';

export const WidgetEvents = () => {
  const widgetEvents = useWidgetEvents();

  useEffect(() => {
    const onRouteExecutionStarted = (route: Route) => {
      console.log('onRouteExecutionStarted fired.');
    };
    const onRouteExecutionUpdated = (update: RouteExecutionUpdate) => {
      console.log('onRouteExecutionUpdated fired.');
    };
    const onRouteExecutionCompleted = (route: Route) => {
      console.log('onRouteExecutionCompleted fired.');
    };
    const onRouteExecutionFailed = (update: RouteExecutionUpdate) => {
      console.log('onRouteExecutionFailed fired.');
    };
    const onRouteHighValueLoss = (update: RouteHighValueLossUpdate) => {
      console.log('onRouteHighValueLoss continued.');
    };
    widgetEvents.on(WidgetEvent.RouteExecutionStarted, onRouteExecutionStarted);
    widgetEvents.on(WidgetEvent.RouteExecutionUpdated, onRouteExecutionUpdated);
    widgetEvents.on(
      WidgetEvent.RouteExecutionCompleted,
      onRouteExecutionCompleted,
    );
    widgetEvents.on(WidgetEvent.RouteHighValueLoss, onRouteHighValueLoss);
    widgetEvents.on(WidgetEvent.RouteExecutionFailed, onRouteExecutionFailed);
    return () => widgetEvents.all.clear();
  }, [widgetEvents]);

  return null;
};
```

Let's do something. How do we check if Javascript has finished loading on the client side of our app? Let's write code that does that.

In your `/app` directory, create a new folder named hooks, and inside it, a file named `useHydrated.tsx` and paste the following code into it

```
import { useSyncExternalStore } from 'react';

function subscribe() {
  return () => {};
}

/**
 * Return a boolean indicating if the JS has been hydrated already.
 * When doing Server-Side Rendering, the result will always be false.
 * When doing Client-Side Rendering, the result will always be false on the
 * first render and true from then on. Even if a new component renders it will
 * always start with true.
 */
export function useHydrated() {
  return useSyncExternalStore(
    subscribe,
    () => true,
    () => false,
  );
}

```

This code lets us check if the JavaScript has finished loading on the client side in our React app. It uses a hook called useHydrated. When you use it, it'll return false during server-side rendering, but once the JavaScript is loaded on the client, it'll switch to true and stay that way. It's a quick way to know if your app is ready to rock on the client side.

You might want to grab a glass of water if you have reached this point. If you did this correctly, your folder structure should look like this:


![Showing folder structure after setting up our app](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6x6w8pm2lezer7le8nqp.png)

Let's edit our `page.tsx` file in the /app Directory. Replace the existing code there with this:

```
import { Widget } from './components/Widget';
import { WidgetEvents } from './components/WidgetEvents';

export default function Home() {
  return (
    <main>
      <WidgetEvents />
      <Widget />
    </main>
  );
}
```

Open your terminal again and use this command to run your server.

```
cd LIFI && yarn dev
```

From my own terminal, it seems like everything is running smooth

![CLI showing the host url](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wzi6szpywa6rv7zw3pkd.png)

Now head on to your browser and visit `localhost:3000`


![Our local hosted web page displaying LIFI widget](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9a5s8d3rtf4lgonvyhv3.png)

## Conclusion

Now, we have our fully functional widget fully integrated in our NextJS App. Do you have any questions or come across any bugs while following this article? Reach out to me on:

Linkedin: [Elisha David](https://linkedin.com/in/Elishaokon13)

X: [Defidevrel](https://x.com/defidevrel)