Core Principles
Modular Approach
This library heavily utilizes Yandex.Maps API module system to make amount of downloaded and executed code from Yandex.Maps as minimal as possible. There are some pros and cons to this system and there are also a way to opt out of this completely.
By default, this library will download only the modules that are actually
rendered on the page. If <Placemark />
or <ObjectManager />
is not mounted
in the page, corresponding would not be downloaded.
That means that the amount of code your clients will download and execute will be as minimal as possible. On the other hand that means that instead of getting a lot of familiar Yandex.Maps API modules by default, now you need to really think about what you are using on the page.
In the example below, we are mounting Map with a Placemark on the page:
You can notice that all map controls that are usually provided on the map by default are missing here. This is happening because they are not part of the "core" Yandex.Maps module, not they are part of the Map or Placemark module.
Loading Modules with modules
Prop
Let's fix this by specifying which controls we want exactly in the map state
and then let's use the modules
prop to load the ones we need:
Nice! Now we have controls on the map and we also avoided downloading the full package of Yandex.Maps API.
All components in this library support modules
prop, that will allow you to
download additional modules when they are needed.
Let's add another one to the example above. This time we will add balloon to the placemark. Balloon module is not downloaded with the base minimum bundle of Yandex.Maps API, so to actually see ballon we need to specify balloon addon as a module on the Placemark component.
Loading Modules With YMaps Provider query
Prop
Manually specifying required modules is not the only way to load them. You can
also take advantage of load
option when you are specifying query
on your
Provider component.
This option is part of Yandex.Maps API request and can be used to define what modules you want to load right away with the Yandex.Maps API.
Lets see how the previous example could be changed to use this option:
Notice how we removed all modules
props from all components and used
query.load
prop instead to specify all modules that are required.
Yandex.Maps API default value for this option is package.full
. Setting
query.load
to 'package.full'
will set this library to the mode that is
completely matching the default Yandex.Maps API behavior
You can learn more about Yandex.Maps API on-demand module system and API loading parameters in Yandex.Maps documentation.
Controlled and Uncontrolled Components
Important React pattern that you should be aware of when using this library is controlled and uncontrolled components. This pattern is all about who is responsible for handling updates and storing components state.
Applied to this library, that means that based on which props you are using, either Yandex.Maps API or your application will be responsible for being the source of truth for your map objects.
In the example below, map state (more specifically zoom and coordinates) is
controlled by application on the first map component, but is not controlled by
application on the second map component. When you click the button, first map
zoom and coordinates will be updated, but the second map will preserve its
state. This happens because instead of state
prop, we are using defaultState
prop.
import React from 'react';
export default function App() {
const [zoom, setZoom] = React.useState(9);
const mapState = React.useMemo(
() => ({ center: [55.75, 37.57], zoom }),
[zoom]
);
return (
<YMaps>
<>
<table>
<tbody>
<tr>
<th>Controlled Map</th>
<th>Uncontrolled Map</th>
</tr>
<tr>
<td>
<Map state={mapState} />
</td>
<td>
<Map defaultState={mapState} />
</td>
</tr>
</tbody>
</table>
<p>
<button onClick={() => setZoom((zoom) => (zoom === 9 ? 12 : 9))}>
Toggle map zoom
</button>
</p>
</>
</YMaps>
);
}
Every prop on every map object is this library supports the default
version
(e.g, state
and defaultState
, options
and defaultOptions
, properties
and defaultProperties
, geometry
and defaultGeometry
). By choosing to use
default
version you are opting out of this library updating map objects when
the props are changed.
As mentioned in the "What Is Supported" section, there is no way to prevent Yandex.Maps from updating maps objects state completely, so it is very easy to go out of sync if you are using these components in a controlled way and not synchronizing the state back to your application state.
From the personal experience, you would want to use default
props for most of
the cases in your application.
If you want to know more about controlled and uncontrolled components, there are a few useful links from React documentation:
React Context. Provider and Consumer Components
This library uses React Context API to provide Yandex.Maps API to every component, that needs it.
This library also uses React Context API so parent Yandex.Maps objects (e.g., Map, Clusterer, ObjectManager) could provide children Yandex.Maps objects with a parent instance.
If you want to know more about React Context and Provider/Consumer components, you can check out React documentation section on the topic.
Make sure that you used YMaps provider component and all Yandex.Maps objects are inside this component tree. This library will throw an error, if the Yandex.Maps context is missing.