I have recently upgraded to developer edition 1.12 and I have encountered a bug which prevents one of my custom widgets from loading part of the time. I have traced the error back to jimuMapView evaluating as null despite the fact that it is actually loaded.
The following works 100% of the time in 1.11, but only about 75% of the time in 1.12. My widget is loaded within a section that is not the active view when the page is loaded. The most reliable way to trigger the bug is to launch the page from the Preview in the builder mode. Reloading the Preview usually loads the widget correctly. Using the buttons within my custom widget will also clear the error and cause the rest of the widget to load correctly.
const viewManager = MapViewManager.getInstance()
const jimuMapView = viewManager.getJimuMapViewById(viewManager.getAllJimuMapViewIds()[0])
useEffect(() => {
console.log('using effect')
console.log('jimuMapView', jimuMapView)
if (jimuMapView) {
console.log('jimuMapView exists')
reactiveUtils.whenOnce(() => jimuMapView.view.ready)
.then(() => {
setMapReady(true)
}
)
})
}
}, [jimuMapView])
The mapReady state variable triggers the child components which load a custom basemap gallery from the API.
In the breaking changes for 1.12 they have a section describing how to wait for the jimuMapView. I use the same method as you've described but I'm thinking I should change my code to use whenJimuMapViewLoaded.
The loading process is actually failing at the if statement before getting to the reactiveUtils line. I have tried using whenJimuMapViewLoaded and pushing jimuMapView into state, but neither changes the behavior of the code. Removing the if statement will cause the widget to crash completely if jimuMapView === null.
From my further investigations, I have determined that this problem is caused by a race condition between my widget and the map widget. If my widget loads before jimuMapView, jimuMapView will evaluate as null and my widget will not fully load. Ideally, I would pull jimuMapView from props and this race condition would not be an issue. Does anyone know how to do that?
I have a workaround involving setTimeout.
const viewManager = MapViewManager.getInstance()
const jimuMapView = viewManager.getJimuMapViewById(viewManager.getAllJimuMapViewIds()[0])
const [counter, setCounter] = useState(0)
const checkMap = () => {
if (counter >= 10) {
return
} else {
setTimeout(() => {
console.log('from timeout')
console.log(counter)
setCounter(counter + 1)
}, 1000)
}
}
useEffect(() => {
console.log('using effect')
console.log('jimuMapView', jimuMapView)
if (jimuMapView) {
console.log('jimuMapView exists')
jimuMapView.whenJimuMapViewLoaded().then(() => {
console.log('map ready')
setMapReady(true)
})
} else {
checkMap()
}
}, [counter])
Essentially if jimuMapView is null, wait a second and reload the widget.