Skip to main content

Sample Code with React

Load SDK

Load NAM SDK in the application's index page.

<!DOCTYPE html>
<html lang="en">
<head>
<title>React App</title>
<script async src="https://ssl.pstatic.net/tveta/libs/glad/prod/gfp-core.js"></script>
</head>
<body>
<div id="root"></div>
</body>
</html>
warning

The NAM SDK must be loaded only once.

To ensure this, it is recommended to load the SDK by adding the script inside <head> tag of initial index.html template. However, if you plan to dynamically load the SDK inside a React component, be careful to avoid loading the SDK multiple times.

SDK Invocation

When calling methods of the NAM SDK, you must use the Command Queue to ensure the SDK has been fully initialized.

In React, you can define a Custom Hook to simplify the process of calling SDK methods without needing to use the command queue every time.

This hook delays rendering using Suspense until the SDK is initialized. It ensures the SDK's initialization state and allows you to access SDK methods in a type-safe manner.

use-glad-sdk.ts
let sdk;

window.gladsdk = (window.gladsdk || { cmd: [] });
const suspender = new Promise((resolve) => {
window.gladsdk.cmd.push(resolve);
}).then(() => {
sdk = window.gladsdk;
});

export function useGladSdk() {
if (!sdk) {
throw suspender;
}
return sdk;
}
MyComponent.tsx
import { Suspense } from 'react';
import { useGladSdk } from './use-glad-sdk';

const MyAd = () => {
const gladSdk = useGladSdk();

useEffect(() => {
const adSlot = gladSdk.defineAdSlot({
adUnitId: 'ad_unit_id',
adSlotElementId: 'slot',
});
gladSdk.displayAd(adSlot)
}, [gladSdk]);

return <div id="slot" />
}

const MyComponent = () => {
return (
// Fallback is rendered if the SDK is not initialized
<Suspense fallback={null}>
<MyAd />
</Suspense>
)
}

Define an Ad Slot

When displaying multiple ad units, you can improve code reusability by defining a Hook and component to manage the ad slots.

use-ad-slot.ts
import { useEffect, useRef } from 'react';
import { useGladSdk } from './use-glad-sdk';

type AdSlotInfo = Record<string, any>;
type AdEventListener = (ad: any, error?: unknown) => void;
interface AdEventListeners {
onAdLoaded?: AdEventListener;
onAdClicked?: AdEventListener;
onAdImpressed?: AdEventListener;
onAdMuteCompleted?: AdEventListener;
onError?: AdEventListener;
}
const defaultListeners = {};

/**
* A Hook that creates an AdSlot for the given AdSlotInfo and adds an event listener to the AdSlot.
*/
export function useAdSlot(adSlotInfo: AdSlotInfo, eventListeners: AdEventListeners = defaultListeners) {
const gladSdk = useGladSdk();
const [adSlot, setAdSlot] = useState(() => gladSdk.defineAdSlot(adSlotInfo));
const adSlotInfoRef = useRef<AdSlotInfo>();
const eventListenersRef = useRef(eventListeners);

if (!deepEqual(adSlotInfoRef.current, adSlotInfo)) {
adSlotInfoRef.current = adSlotInfo;
}
const optimalAdSlotInfo = adSlotInfoRef.current;

useEffect(() => {
const _adSlot = gladSdk.defineAdSlot(optimalAdSlotInfo);
setAdSlot(_adSlot);
return () => {
gladSdk.destroyAdSlots([_adSlot]);
};
}, [gladSdk, optimalAdSlotInfo]);

useEffect(() => {
eventListenersRef.current = eventListeners;
}, [eventListeners]);

useEffect(() => {
const eventMap: Record<string, string> = {
[gladSdk.event.AD_LOADED]: 'onAdLoaded',
[gladSdk.event.AD_CLICKED]: 'onAdClicked',
[gladSdk.event.AD_IMPRESSED]: 'onAdImpressed',
[gladSdk.event.AD_MUTE_COMPLETED]: 'onAdMuteCompleted',
[gladSdk.event.ERROR]: 'onError',
};
const disposers = Object.entries(eventMap).map(([event, listenerName]) => {
const listener: AdEventListener = (ad, error) => {
if (ad.slot !== adSlot) return;
eventListenersRef.current[listenerName]?.(ad, error);
}
gladSdk.addEventListener(event, listener);
return () => gladSdk.removeEventListener(event, listener);
});
return () => {
disposers.forEach((dispose) => dispose());
};
}, [gladSdk, adSlot]);

return adSlot;
};

function deepEqual(a: unknown, b: unknown): a is typeof b {
// implement your deep compare method for better stability.
return JSON.stringify(a) === JSON.stringify(b)
}
NaverAd.tsx
import { ComponentPropsWithoutRef, ComponentRef, forwardRef } from 'react';

type NaverAdRef = ComponentRef<'div'>;
type NaverAdProps = ComponentPropsWithoutRef<'div'> & {
adSlot: any;
};

/**
* A component that takes an AdSlot as props and creates an element to display the ad.
*/
export const NaverAd = forwardRef<NaverAdRef, NaverAdProps>((props, ref) => {
const { adSlot, ...divProps } = props;

return <div {...divProps} ref={ref} id={adSlot.getAdSlotElementId()} />;
});
NaverAd.displayName = 'NaverAd';

Dispay ads

Display ads using the defined Hooks and components above.

MyComponent.tsx
import { useEffect } from 'react';
import { NaverAd } from './NaverAd';
import { useAdSlot } from './use-ad-slot';
import { useGladSdk } from './use-glad-sdk';

const adSlotInfo = {
adUnitId: 'ad_unit_id',
adSlotElementId: 'slot',
uct: 'KR',
customParam: {
category: 'entertainment',
hobby: ['music', 'sports'],
},
};

const MyComponent = () => {
const gladSdk = useGladSdk();
const adSlot = useAdSlot(adSlotInfo, {
onAdLoaded(ad: any) {
// @TODO implements code
},
onAdClicked(ad: any) {
// @TODO implements code
},
});

useEffect(() => {
gladSdk.displayAd(adSlot);
}, [gladSdk, adSlot]);

return (
<NaverAd adSlot={adSlot} />
);
}