Integration with Next.js
This article describes the integration with App Router for Next.js version 13 and above.
Note
Integration with Next.js is based on using the @yandex/ymaps3-reactify module.
Before reading this article, we recommend familiarizing yourself with the integration with React JS.
Step 1. Connecting the API
First, you need to connect the API using the <Script /> component:
import Script from 'next/script';
export default function RootLayout({children}) {
return (
<html>
<body>
{children}
<Script src="https://api-maps.yandex.ru/v3/?apikey=YOUR_API_KEY&lang=en_US" strategy="beforeInteractive" />
);
}
Warning
It is important to specify the script loading strategy beforeInteractive.
This will allow the API to load before Next.js begins page hydration.
Step 2. Connecting the @yandex/ymaps3-reactify module
In App Router, each page is a server component, the code for which is not executed in the browser.
Let's create a Map component and add the use client directive so that the component's code executes in the browser.
'use client';
const Map = () => {
return null;
};
export default Map;
Now the component's code is executed twice: in the browser and on the server.
The @yandex/ymaps3-reactify module does not support server rendering.
To ensure the module loads only in the browser, we use React.useEffect.
'use client';
import * as React from 'react';
import * as ReactDOM from 'react-dom';
const Map = () => {
const [reactifiedApi, setReactifiedApi] = React.useState();
React.useEffect(() => {
Promise.all([
ymaps3.import('@yandex/ymaps3-reactify'),
ymaps3.ready
]).then(([{reactify}]) =>
setReactifiedApi(reactify.bindTo(React, ReactDOM).module(ymaps3))
);
}, []);
return null;
};
export default Map;
Now we can use @yandex/ymaps3-reactify for rendering the map.
'use client';
import * as React from 'react';
import * as ReactDOM from 'react-dom';
const Map = () => {
const [reactifiedApi, setReactifiedApi] = React.useState();
React.useEffect(() => {
Promise.all([
ymaps3.import('@yandex/ymaps3-reactify'),
ymaps3.ready
]).then(([{reactify}]) =>
setReactifiedApi(reactify.bindTo(React, ReactDOM).module(ymaps3))
);
}, []);
if (!reactifiedApi) {
return null;
}
const {YMap, YMapDefaultSchemeLayer, YMapDefaultFeaturesLayer} = reactifiedApi;
return (
<YMap location={{center: [37.588144, 55.733842], zoom: 9}}>
<YMapDefaultSchemeLayer />
<YMapDefaultFeaturesLayer />
</YMap>
);
};
export default Map;
'use client';
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import {ReactifiedModule} from '@yandex/ymaps3-types/reactify/reactify';
import {LOCATION} from '../variables';
type ReactifiedApi = ReactifiedModule<typeof ymaps3>;
const Map = () => {
const [reactifiedApi, setReactifiedApi] = React.useState<ReactifiedApi>();
React.useEffect(() => {
Promise.all([
ymaps3.import('@yandex/ymaps3-reactify'),
ymaps3.ready
]).then(([{reactify}]) =>
setReactifiedApi(reactify.bindTo(React, ReactDOM).module(ymaps3))
);
}, []);
if (!reactifiedApi) {
return null;
}
const {YMap, YMapDefaultSchemeLayer, YMapDefaultFeaturesLayer} = reactifiedApi;
return (
<YMap location={LOCATION}>
<YMapDefaultSchemeLayer />
<YMapDefaultFeaturesLayer />
</YMap>
);
};
export default Map;
import * as React from 'react';
import Script from 'next/script';
import Map from '@/components/map';
export default function Home() {
return (
<>
<Script
src="https://api-maps.yandex.ru/v3/?apikey=YOUR_API_KEY&lang=en_US"
strategy="beforeInteractive"
/>
);
}
import * as React from 'react';
export default function RootLayout({
children
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html>
<body style={{padding: 0, margin: 0}}>
{children}
</body>
</html>
);
}
import type {YMapLocationRequest} from '@yandex/ymaps3-types';
export const LOCATION: YMapLocationRequest = {
center: [37.623082, 55.75254], // starting position [lng, lat]
zoom: 9 // starting zoom
};