Search code examples
reactjsgoogle-mapskonvajsreact-google-mapsreact-konva

How to get rid of 'Text components are not supported for now in ReactKonva. You text is: "Loading..."' using react-konva and react-google-maps/api?


I want to render a Konva shape on top of a Google Maps layer. Since I'm using React, I use react-konva and react-google-maps/api libraries to work with.

Everytime I run yarn start, I get this error: Text components are not supported for now in ReactKonva. You text is: "Loading..."

Versions

  • react-konva: "16.13.0-6"
  • react-google-maps/api: "1.9.12"
  • konva: "7.0.6"
  • Chrome: "85.0.4183.83"

Project directory structure

It's a simple app built using create-react-app.

.
├── Makefile
├── README.md
├── Vagrantfile
├── bootstrap.sh
├── package.json
├── public
│   ├── classic-outline.png
│   ├── favicon.ico
│   ├── index.html
│   ├── logo192.png
│   ├── logo512.png
│   ├── manifest.json
│   └── robots.txt
├── src
│   ├── App.css
│   ├── App.js
│   ├── App.test.js
│   ├── components
│   │   ├── KonvaShape.js
│   │   └── Map.js
│   │  
│   ├── index.css
│   ├── index.js
│   ├── serviceWorker.js
│   └── setupTests.js
└── yarn.lock

Here are my components:

App.js

import React from 'react';

import './App.css';

import KonvaShape from './components/KonvaShape';

function App() {
    return (
        <div>
            <KonvaShape />
        </div>
    );
}

export default App;

KonvaShape.js

import React from 'react';
import { Stage, Layer } from 'react-konva';

import Map from './Map';

function KonvaShape() {

    return (
        <Stage width={window.innerWidth / 2} height={window.innerHeight / 2}>
            <Layer>
                <Map />
            </Layer>
        </Stage>
    );
}

export default KonvaShape;

Map.js

import React from 'react';
import { GoogleMap, LoadScript } from '@react-google-maps/api';

const containerStyle = {
  width: '400px',
  height: '400px'
};

const center = {
  lat: -3.745,
  lng: -38.523
};

function Map() {
  const [map, setMap] = React.useState(null);

  const onLoad = React.useCallback(function callback(map) {
    const bounds = new window.google.maps.LatLngBounds();
    map.fitBounds(bounds);
    setMap(map)
  }, [])

  const onUnmount = React.useCallback(function callback(map) {
    setMap(null)
  }, [])

  return (
    <LoadScript
      googleMapsApiKey={"ENTER YOUR GOOGLE MAPS API KEY HERE"}
    >
      <GoogleMap
        mapContainerStyle={containerStyle}
        center={center}
        zoom={10}
        onLoad={onLoad}
        onUnmount={onUnmount}
      >
        { /* Child components, such as markers, info windows, etc. */}
        <></>
      </GoogleMap>
    </LoadScript>
  )
}

export default React.memo(Map)

I am fairly new to React and Konva but my guess is that I should wait Google Maps component to mount before rendering my KonvaShape component. I tried to use KonvaShape own state to manage this trick (as this answer suggest ReactJS: How to render components only after successful asynchronous call?) but I didn't succeed much.


Solution

  • You are trying inject non-konva element here:

    <Stage width={window.innerWidth / 2} height={window.innerHeight / 2}>
      <Layer>
        <Map />
      </Layer>
    </Stage>
    

    It is not possible to do this directly. <Stage /> support only konva nodes. So you can use layers, groups, and shape there.

    If you want to add google maps (that is probably is a DOM component) you have two ways:

    1. Place google maps on top of the stage with absolute position:
    <Stage width={window.innerWidth / 2} height={window.innerHeight / 2}>
     {/* canvas internals */}
    </Stage>
    <div style={{ position: 'absolute', top: 0, left: 0 }}>
      <Map/>
    </div>
    
    1. Or you can try to use the DOM portal to inject map into Konva stage. But that is just a react sugar, internally you will still have absolute position map on top of the stage.