In a React component that I've developed, I have utilized ResizeObserver to track its own width. Within this component, two divs are rendered with each having a "flex: 1" property to ensure equal width distribution. Under certain conditions, such as when the component is too small and specific state requirements are met, the first div's display is set to "none", allowing the second div to occupy the entire width of the flex container.
Although the component effectively responds to changes in browser width, an issue arises when there's a sidebar that can be toggled open or closed in my application. When the sidebar is closed and sufficient width becomes available due to this action, the component should recognize it and readjust to display the "dashboard_monitors" div once again. However, a glitch occurs where initially the sidebar is closed, and the second "dashboard_activity" div occupies the full width before eventually updating to show the "dashboard_monitors" div, resulting in a visible shift as the component realigns each div with equal width.
To harmonize the disappearance of the sidebar and the component update simultaneously, preventing the perceptible jump, a strategy needs to be implemented but I'm uncertain about how to achieve this.
The following is the code snippet for the mentioned component:
import './Dashboard.css'
import MonitorComponent from '../../components/Monitor/Monitor';
import DetailComponent from '../../components/Monitor/Detail';
import { Monitor } from '../../monitor'
import { useEffect, useMemo, useState } from 'react';
import { useWidth } from '../../hooks/useWidth';
interface DashboardProps {
monitors: Monitor[]
focused: Monitor | null,
drafting: boolean,
}
export default function Dashboard(props: DashboardProps) {
const {
monitors,
focused,
drafting,
} = props;
const isEditing = useMemo(() => focused || drafting, [focused, drafting]);
const { width: dashboardWidth, ref: dashboardRef } = useWidth<HTMLDivElement>();
const [sorted, setSorted] = useState<Monitor[]>([])
useEffect(() => {
const sorted = monitors.sort((a, b) => {
if (a.strategy.name > b.strategy.name) {
return 1;
} else {
return -1;
}
});
setSorted(sorted);
}, [monitors])
const dashboardClasses = ['dashboard', isEditing && dashboardWidth < 700 ? 'single' : '']
return (
<div className={dashboardClasses.join(' ')} ref={dashboardRef}>
<div className="dashboard_monitors">
{sorted.map((n, i) =>
<MonitorComponent key={i} monitor={n} />)
}
</div>
{isEditing ?
<div className="dashboard_activity">
<DetailComponent monitor={focused} />
</div>
: null}
</div>
)
}
Here is the CSS styling applied to the component in "Dashboard.css":
.dashboard {
display: flex;
height: 100%;
}
.dashboard.single .dashboard_monitors {
display: none;
}
.dashboard.single .dashboard_activity {
margin-left: 0;
}
.dashboard > * {
flex: 1;
overflow-x: hidden;
overflow-y: auto;
}
.dashboard_activity {
margin-left: var(--padding-2);
}
.dashboard_monitors {
display: grid;
gap: var(--padding-2);
grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
grid-auto-rows: 200px;
padding-right: var(--padding-0);
padding-bottom: var(--padding-0);
}
The ResizeObserver functionality is encapsulated in the useWidth hook presented below:
import { useState, useRef, useEffect } from "react";
export const useWidth = <T extends HTMLElement>() => {
const [width, setWidth] = useState(0);
const ref = useRef<T>(null);
useEffect(() => {
const observer = new ResizeObserver((entries) => {
setWidth(entries[0].contentRect.width);
});
const refElement = ref.current;
if (refElement) {
observer.observe(refElement);
}
return () => {
refElement && observer.unobserve(refElement);
};
}, []);
return { width, ref };
};
If you have any insights or inquiries regarding this matter, I appreciate your valuable input. Thank you for your time.