React
Warning
Supported React version: 16 or higher.
There is a React analog for every imperative API class inherited from MMapEntity. To use the React API version, connect the @mappable-world/mappable-reactify
module:
const mappableReactify = await mappable.import('@mappable-world/mappable-reactify');
const reactify = mappableReactify.reactify.bindTo(React, ReactDOM);
const {MMap, MMapDefaultSchemeLayer, MMapDefaultFeaturesLayer, MMapMarker} = reactify.module(mappable);
Note
The @mappable-world/mappable-reactify
module provides a set of React access methods both for individual objects and modules/packages as a whole. The hierarchy of objects and initialization parameters are the same for most classes.
After connecting the module, use MMapEntity descendant objects as React components:
<MMap location={{center: [25.229762, 55.289311], zoom: 9}} mode="vector">
<MMapDefaultSchemeLayer />
<MMapDefaultFeaturesLayer />
<MMapMarker coordinates={[25.229762, 55.289311]} draggable={true}>
<section>
<h1>You can drag this header</h1>
</section>
</MMapMarker>
</MMap>
Note
The JS API supports integration only with React JS.
React Native is currently not supported.
Quick start
Connecting via top-level-await
<!DOCTYPE html>
<html>
<head>
<!-- Replace YOUR_API_KEY with the real key -->
<script src="https://js.api.mappable.world/v3/?apikey=YOUR_API_KEY&lang=en_US"></script>
</head>
<body>
<div id="root"></div>
</body>
</html>
import ReactDOM from 'react-dom/client';
import App from './App';
const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);
root.render(<App />);
import {MMap, MMapDefaultSchemeLayer, MMapDefaultFeaturesLayer, MMapMarker, reactify} from './lib/mappable';
import type {MMapLocationRequest} from 'mappable';
const LOCATION: MMapLocationRequest = {
center: [25.229762, 55.289311],
zoom: 9
};
export default function App() {
return (
<div style={{width: '600px', height: '400px'}}>
<MMap location={reactify.useDefault(LOCATION)}>
<MMapDefaultSchemeLayer />
<MMapDefaultFeaturesLayer />
<MMapMarker coordinates={reactify.useDefault([25.229762, 55.289311])} draggable={true}>
<section>
<h1>You can drag this header</h1>
</section>
</MMapMarker>
</MMap>
</div>
);
}
import React from 'react';
import ReactDom from 'react-dom';
const [mappableReact] = await Promise.all([mappable.import('@mappable-world/mappable-reactify'), mappable.ready]);
export const reactify = mappableReact.reactify.bindTo(React, ReactDom);
export const {MMap, MMapDefaultSchemeLayer, MMapDefaultFeaturesLayer, MMapMarker} = reactify.module(mappable);
{
"compilerOptions": {
"target": "es2017",
"lib": ["dom", "dom.iterable", "esnext"],
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"jsx": "react-jsx",
"typeRoots": ["./node_modules/@types", "./node_modules/@mappable-world/mappable-types"],
"paths": {
"mappable": ["./node_modules/@mappable-world/mappable-types"]
}
}
}
{
"devDependencies": {
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@mappable-world/mappable-types": "^0.0.10",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-scripts": "5.0.1",
"typescript": "^4.9.5"
},
"scripts": {
"start": "react-scripts start"
}
}
Set dependencies and run a local server:
npm install
npm start
Open the app
Specifics
-
In
package.json
, add a dev dependency on the@mappable-world/mappable-types
package.We recommend installing the latest version:
npm i --save-dev @mappable-world/mappable-types@latest
-
In
tsconfig.json
, setcompilerOptions.typeRoots
with a list of paths to type files. Add a path to the@mappable-world/mappable-types
package there to make themappable
namespace with types appear in the global scope.Note
The
mappable
namespace contains all the class types provided by the JS API, but they are not available in the runtime environment untilmappable.ready
is resolved. -
In
tsconfig.json
, setcompilerOptions.paths
, informing the TS compiler that the contents of the importedmappable
package should be searched for at the specified path. This enables you to import types in project files as if they were located not at@mappable-world/mappable-types
, but in themappable
package:import type {MMapLocationRequest} from 'mappable';
All types must be imported from the root.
The internal structure isn't guaranteed and can change over time.
-
In
tsconfig.json
, for top-level-await to operate correctly, thecompilerOptions.module
parameter must be set to one of the following values:es2022
,esnext
,system
, orpreserve
. ThecompilerOptions.target
parameter must be set toes2017
or higher. -
Connect the
@mappable-world/mappable-reactify
module. Inlib/mappable.ts
, wait until the JS API and Reactify module are fully loaded and then export the necessary map components so that they can be used in other parts of the project:import React from 'react'; import ReactDom from 'react-dom'; const [mappableReact] = await Promise.all([mappable.import('@mappable-world/mappable-reactify'), mappable.ready]); export const reactify = mappableReact.reactify.bindTo(React, ReactDom); export const {MMap, MMapDefaultSchemeLayer, MMapDefaultFeaturesLayer} = reactify.module(mappable);
Note
The
@mappable-world/mappable-reactify
module provides a set of React access methods both for individual objects and modules/packages as a whole. The hierarchy of objects and initialization parameters are the same. -
The use of top-level-await in
lib/mappable.ts
guarantees thatmappable.ready
andmappable.import('@mappable-world/mappable-reactify')
are executed before the map components are imported, allowing any JS API objects to be used as React components synchronously:<MMap location={reactify.useDefault(LOCATION)}> <MMapDefaultSchemeLayer /> <MMapDefaultFeaturesLayer /> ... </MMap>
reactify.useDefault
MMap
and all other components are uncontrolled. Components use the imperative interface of the library (for example, MMapZoomControl
calls MMap.update({location})
). This may cause desynchronizing with the state and parameters in React (for example, location
for MMap
or coordinates
for MMapMarker
with dragging enabled).
Use reactify.useDefault(value)
to set a component parameter only once and not update it on re-renders. For example, <MMap location={reactify.useDefault({center, zoom})}/>
will behave as <input defaultValue={''}/>
.
To control parameter updates, use the second reactify.useDefault(value, deps)
parameter: an array of dependencies as in React hooks (for example, useCallback
, useMemo
, useEffect
). The parameter will be updated if the dependency array is different.
For parameters with objects, the value itself can be used as a dependency. Re-rendering occurs only if the values are different. For example, const [location, setLocation] = useState(...)
, reactify.useDefault(location, [location])
, setLocation({...})
.
reactify.useDefault
works with any parameters of any components from reactify
.
Warning
reactify.useDefault
returns an object with no public contract and should be used only directly in component parameters.
Custom implementations of mappable.MMapEntity objects for React
Use the overrideKey
key to determine custom implementations of mappable.MMapEntity objects for reactify:
type MMapSomeClassProps = {
id: string;
};
export class MMapSomeClass extends mappable.MMapComplexEntity<MMapSomeClassProps> {
static [mappableReactify.reactify.overrideKey] = MMapSomeClassReactifyOverride;
//...
}
and the method for determining a custom implementation:
export const MMapSomeClassReactifyOverride = (
MMapSomeClassI, // base MMapSomeClass class
{reactify, React}
) => {
const MMapSomeClassReactified = reactify.entity(MMapSomeClassI); // Standard reactify method
const MMapSomeClassR = React.forwardRef((props, ref) => {
return (<>
<MMapSomeClassReactified {...props} ref={ref} ... />
</>);
})
return MMapSomeClassR;
}
and add the resulting component to the app:
import {MMapSomeClass} from './some-class';
import React from 'react';
import ReactDOM from 'react-dom';
// ...
const mappableReactify = await mappable.import('@mappable-world/mappable-reactify');
const reactify = mappableReactify.reactify.bindTo(React, ReactDOM);
const MMapSomeClassR = reactify.entity(MMapSomeClass);
function App() {
return <MMapSomeClassR id="some_id" />;
}
An open-source JavaScript library for creating application UIs.
An open-source JavaScript framework that came after React JS. It is used to develop mobile and web applications.