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 @mappable-world/mappable-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://js.api.mappable.world/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.
@mappable-world/mappable-reactify
module
Step 2. Connecting the 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 @mappable-world/mappable-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([mappable.import('@mappable-world/mappable-reactify'), mappable.ready]).then(([{reactify}]) =>
setReactifiedApi(reactify.bindTo(React, ReactDOM).module(mappable))
);
}, []);
return null;
};
export default Map;
Now we can use @mappable-world/mappable-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([
mappable.import('@mappable-world/mappable-reactify'),
mappable.ready
]).then(([{reactify}]) =>
setReactifiedApi(reactify.bindTo(React, ReactDOM).module(mappable))
);
}, []);
if (!reactifiedApi) {
return null;
}
const {MMap, MMapDefaultSchemeLayer, MMapDefaultFeaturesLayer} = reactifiedApi;
return (
<MMap location={{center: [25.229762, 55.289311], zoom: 9}}>
<MMapDefaultSchemeLayer />
<MMapDefaultFeaturesLayer />
</MMap>
);
};
export default Map;
'use client';
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import {ReactifiedModule} from '@mappable-world/mappable-types/reactify/reactify';
import {LOCATION} from '../variables';
type ReactifiedApi = ReactifiedModule<typeof mappable>;
const Map = () => {
const [reactifiedApi, setReactifiedApi] = React.useState<ReactifiedApi>();
React.useEffect(() => {
Promise.all([mappable.import('@mappable-world/mappable-reactify'), mappable.ready]).then(([{reactify}]) =>
setReactifiedApi(reactify.bindTo(React, ReactDOM).module(mappable))
);
}, []);
if (!reactifiedApi) {
return null;
}
const {MMap, MMapDefaultSchemeLayer, MMapDefaultFeaturesLayer} = reactifiedApi;
return (
<MMap location={LOCATION}>
<MMapDefaultSchemeLayer />
<MMapDefaultFeaturesLayer />
</MMap>
);
};
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://js.api.mappable.world/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 {MMapLocationRequest} from '@mappable-world/mappable-types';
export const LOCATION: MMapLocationRequest = {
center: [55.44279, 25.24613], // starting position [lng, lat]
zoom: 9 // starting zoom
};