Integration with React

Note

The JS API supports integration with React JS only.

At the moment, there is no support for React Native.

Quick start

Warning

Supported React version: at least 16

For each object in the JS API, there is a React analog. To use React's API version, use 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 methods for accessing React to both individual objects and modules/packages in general. The hierarchy of objects and initialization parameters is the same.

After connecting the module, use any JS API objects as React components:

<MMap location={reactify.useDefault({center: [25.229762, 55.289311], zoom: 9})} mode="vector">
  <MMapDefaultSchemeLayer />
  <MMapDefaultFeaturesLayer />

  <MMapMarker coordinates={reactify.useDefault([25.229762, 55.289311])} draggable={true}>
    <section>
      <h1>You can drag this header</h1>
    </section>
  </MMapMarker>
</MMap>

reactify.useDefault

MMap and all other components are uncontrollable by design. Components use imperative API (e.g. MMapZoomControl calls MMap.update({location})). This may cause desynchronization with props and state in React (e.g. location in MMap or coordinates on MMapMarker with enabled drag).

Use reactify.useDefault(value) to set prop once and don't update it in rerenders.
E.g. <MMap location={reactify.useDefault({center, zoom})}/> will behave like <input defaultValue={''}/>.

To precisely control prop update pass array of dependencies as a second argument to reactify.useDefault(value, deps) like in React hooks (e.g. useCallback, useMemo, useEffect).
Prop will be updated if dependencies array differs from the last one.

For object parameters value itself can be used as a dependency, if value references differ. E.g. const [location, setLocation] = useState(...), reactify.useDefault(location, [location]), setLocation({...}).

reactify.useDefault works with any prop of any component returned from reactify.

Warning

reactify.useDefault returns opaque object with no public API and MUST be used only directly in props.

Custom implementations of objects mappable.MMapEntity for React

Use the overrideKey key to define a custom implementation of mappable.MMapEntity objects for reactify:

type MMapSomeClassProps = {
  id: string;
};
export class MMapSomeClass extends mappable.MMapComplexEntity<MMapSomeClassProps> {
  static [mappableReactify.reactify.overrideKey] = MMapSomeClassReactifyOverride;
  //...
}

and define a method for determining user implementation:

export const MMapSomeClassReactifyOverride = (
  MMapSomeClassI, // MMapSomeClass base 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 application:

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" />;
}
Previous
Next