Skip to content

The Map component's declared event listeners are being re-attached on every state update #773

Closed
@shawncrawley

Description

@shawncrawley

I discovered that the Map component's declared event listeners are being re-attached on every state update, which results in the listener firing n times per click, where n is the number of times the parent component's state has been updated since its initial render.

Here's a minimal example, which can be copied and pasted into https://code.esm.sh and reproduced by clicking on the map a few times and then opening the console and checking the log statements. The first click yields one log statement, while the second click results in two (i.e. three total), the third in three (six total), and so forth.

<!DOCTYPE html>
<html>

<head>
  <title>@planet/maps with esm.sh</title>
  <script type="importmap">
    {
      "imports": {
        "htm": "https://esm.sh/htm",
        "react": "https://esm.sh/[email protected]",
        "react-dom/": "https://esm.sh/[email protected]/",
        "@planet/maps/": "https://esm.sh/@planet/maps/"
      }
    }
  </script>
  <link href="https://esm.sh/[email protected]/ol.css" rel="stylesheet">
  <style>
    html,
    body {
      margin: 0;
    }

    #root {
      position: absolute;
      top: 0;
      height: 100%;
      width: 100%;
    }
  </style>
</head>

<body>
  <div id="root"></div>
  <script type="module">
    import Map from '@planet/maps/Map';
    import View from '@planet/maps/View';
    import ScaleLine from '@planet/maps/control/ScaleLine';
    import TileLayer from '@planet/maps/layer/WebGLTile';
    import OSM from '@planet/maps/source/OSM';
    import htm from 'htm';
    import React from 'react';
    import {createRoot} from 'react-dom/client';

    const html = htm.bind(React.createElement);

    function App() {
      const [count, setCount] = React.useState(0);
      return html`
        <div>Count is ${count}</div>
        <${Map} onClick=${(e)=> console.log("CLICK") || setCount(count+1)} style=${{width: '100%', height: '100%'}}>
          <${View} options=${{center: [0, 0], zoom: 1}} />
          <${TileLayer}>
            <${OSM} />
          </${TileLayer}>
          <${ScaleLine} />
        </${Map}>
      `;
    }

    const root = createRoot(document.getElementById('root'));
    root.render(html`<${App} />`);
  </script>
</body>

</html>

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions