I have a class inheriting React.Component as such :
import { Component } from "react"
import {Map} from "ol" // the goal is to render a map with openlayers
import './MapCanvas.css'
class MapCanvas extends Component {
constructor(props) {
super(props)
this.state = {}
}
componentDidMount() {
console.log('hello') // called twice
const canvas = new Map(/* map options, irrelevant here */)
this.setState({canvas})
}
componentWillUnMount () {
console.log('goodbye') // never called
if (this.state && this.state.canvas) {
this.state.canvas.setTarget(undefined) // should remove the map
}
}
render() {
return (
<div id="map" className="map"></div>
)
}
}
export default MapCanvas
My app looks like this
import MapCanvas from './components/MapCanvas'
import './App.css'
function App() {
return (
<MapCanvas/>
)
}
export default App
and index is
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import App from './views/App';
const root = createRoot(document.getElementById('app'))
root.render(
<StrictMode>
<App/>
</StrictMode>
)
If I remove StrictMode, Everything looks fine,
However if I leave it, the componentDidMount method of MapCanvas gets called twice, and I end up having 2 maps on the page. componentWillUnmount never gets called in the process.
I read here and there that React StrictMode calls some functions multiple times in Developpement mode.
As far as I understood, it is to help us code in a cleaner way, but I can't understand what I am supposed to do.
My question is, where am I supposed to setup the ol.Map so that it respects the best practices and gets called only once, OR gets properly "destroyed" on update ?
just as posting the question I realized I had a typo on componentWillUnmount (M instead of m)
I Corrected it, now I see "goodbye" in the console, but I still have 2 maps.
If this question is more about openlayer thant about react, let it know in the comments and I'll update or delete it
Using class attributes instead of React state to store the canvas gives the expected result. Is this considered good practice or is there a better way ?
Here is a workaround that worked for me: using a class attribute instead of the React State
import { Component, createRef } from "react"
import { Map } from "ol"
class MapCanvas extends Component {
constructor(props) {
super(props)
this.canvas = new Map(/* options */)
this.ref = createRef()
}
componentDidMount() {
this.canvas.setTarget(this.ref.current)
}
componentWillUnmount () {
this.canvas.setTarget(undefined)
}
render() {
return (
<div ref={this.ref} className="map"></div>
)
}
}
export default MapCanvas
It may not be good react practice, but it solves the prolem for now
If you have a better solution you can post an answer i'll consider accepting it instead