ymaps3 - Карта ре-инициализируется при любой манипуляции с DOM

Пытаюсь сделать обертку для Yandex Map Api 3 для реакта.

Создаю контекст, в контексте через useSyncExteranlStore загружаю скрипт. Получаю экземпляр yamps и reactify:

const YMapsProvider = ({
  apikey,
  lang,
  children,
}: YMapsProviderProps): JSX.Element => {
  const state = useSyncExternalStore(
    store.subscribe,
    () => store.getState(),
    () => ({
      reactify: null,
      ymaps: null,
    })
  );

  useIsomorphicEffect(() => {
    if (apikey) initializeAction({ apikey, lang });
  }, [apikey, lang]);

  return (
    <ymapsContext.Provider
      value={{
        ymaps: state.ymaps,
        reactify: state.reactify,
      }}
    >
      {children}
    </ymapsContext.Provider>
  );
};

Дальше внутри компонентов карт читаю контекст и выпускаю экземпляр компонента:

export const YMap: typeof YMapReact = ({ ...props }) => {
  const { reactify, ymaps } = useYMapsContext();
  if (!reactify || !ymaps) return null;
  const Component = reactify.module(ymaps)["YMap"];
  return <Component {...props} />;
};

С этим все хорошо, но любая манипуляция, например setState вызывает реинициализацию карты. Через несколько манипуляций в окне браузера вылетает warning:

WARNING: Too many active WebGL contexts. Oldest context will be lost.

Пробовал создавать компоненты через useMemo, useCallback, createElement, forwardRef и т.п., передавать yamps и reactify как рефы т.п.

Судя по всему либо в контексте чего-то не хватает, либо...

Буду признателен за любые идеи

Репозиторий: https://github.com/antokhio/next-ymaps3-issue

Постарался максимально убрать лишний код.


Ответы (1 шт):

Автор решения: antokhio

При помощи поддержки Яндекс карт удалось решить проблему:

Суть в том, что reactify выпускает новый инстанс компонента при каждом обращении, поэтому меморизировать необходимо именно его:

import { YMap as YMapReact } from "@yandex/ymaps3-types/react";
import { useYMapsContext } from "./YMapsProvider";
import React, { useMemo } from "react";

export const YMap = React.forwardRef(({ ...props }: any, ref: any) => {
  const value = useYMapsContext();

  const Component: typeof YMapReact | null = useMemo(() => {
    if (value.reactify && value.ymaps) {
      return value.reactify.module(value.ymaps)["YMap"];
    } else return null;
  }, [value.reactify]);

  return Component ? (
    <Component ref={ref} {...props} />
  ) : (
    <>loading</>
  );
});

YMap.displayName = "YMap";

Рабочая версия.

→ Ссылка