I have been trying to figure out how to find the inner width of a container with Ionic React.
Normally in plain old React it would be as simple as using a ref
and then. querying ref.current.offsetWidth
in either componentDidMount or using useEffect
with an empty dependency array as a couple of examples.
When I try to query ref.current.offsetWidth
in a componentDidMount
type context it always resolves to 0. I tried to set a timeout to see if this makes a difference and indeed it does. If I set a timeout for 700ms or more then I do get the width correctly. If it is any less than 700ms then it is 0. I can even visually see the element on the screen before this but the value of the ref width is 0. I appreciate processor speed etc may affect the time.
I sanity checked that I was not doing something silly by spinning up a standard create-react-app project. I pasted over my code and I got the ref immediately in componentDidMount
.
@mhartington told me in this thread (that digressed) that I should use Ionic Lifecycle Hooks.
I tried the following:
useIonViewWillEnter(() => {
console.log("I am about to enter!",wrapperRef.current.offsetWidth);
});
useIonViewDidEnter(() => {
console.log("I am entered!",wrapperRef.current.offsetWidth);
});
Both resolve to 0 still, unless I use a timeout of couse.
Lastly, the effect I am experiencing is that when a Google Geochart has been rendered once, and navigated away from, then its width seems to collapse. I wonder if this is something in the Router animation?
Please see example:
On first load:
Ionic Router Cached version:
Any help would be greatly appreciated.
Can you put this into an example to test it out ?
Instead of a setTimeout, you could always use a requestAnimationFrame, which will be a bit more performant
Thanks @mhartington,
I will get something together and post it. I appreciate the support. I have a meeting with your team next week to discuss premium support options going forward.
Have a good weekend.
useIonViewDidEnter(()=> {
console.log(wrapperRef!.current!.offsetWidth);
})
Use the life-cycle hook
Thanks Mike,
Are you seeing the issue with the map width collapsing once the page has been cached? I do not get this behaviour in create-react-app (tested). For some reason when Ionic is caching the page the map collapses its width.
You seem to have a big misunderstanding about what is going on in the app.
The caching has nothing to do with the map changes.
It’s related to the animations that happen and the chart constantly rerendering (over-rendering IMO).
You can see this by just resizing the browser window. So if the chart/map is constantly rerendering any change, any animations that are happening (which we do in Ionic) are going to affect the chart.
Basically, it seem like the chart needs to be added/removed from the DOM to stop it from over-rendering. Here’s a simplified version of what you could do.
import React, { useState } from 'react';
import {
IonContent,
IonHeader,
IonPage,
IonTitle,
IonToolbar,
IonButton,
useIonViewWillEnter,
useIonViewWillLeave,
} from '@ionic/react';
import './Home.css';
import Chart from 'react-google-charts';
import mapRegions from '../mapRegions';
const styles = {
width: '100%',
height: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
};
const Test: React.FC = () => {
const [renderChart, setRenderChart] = useState(false);
useIonViewWillEnter(() => {
setRenderChart(true);
});
useIonViewWillLeave(() => {
setRenderChart(false);
});
return (
<IonPage>
<IonHeader>
<IonToolbar>
<IonTitle>Blank</IonTitle>
</IonToolbar>
</IonHeader>
<IonContent>
<IonButton routerLink="/home">Test</IonButton>
<div style={styles} ref={wrapperRef}>
{renderChart ? <MyChart /> : null}
</div>
</IonContent>
</IonPage>
);
};
const MyChart = () => (
<Chart
width="100%"
height="100%"
chartType="GeoChart"
data={mapRegions}
options={{
colorAxis: { colors: ['#ccc', 'orange'] },
legend: 'none',
}}
mapsApiKey="******"
/>
);
export default Test;
Another option is to create your own chart component instead where you could control the rendering
1 Like