Where to set the height of a component in the lifecycle? - javascript

I have a problem where I am using a React grid component in order to display multiple charts. If you imagine the webpage is a 4 x 4 grid and I have two charts. Each chart being a 4 x 2 grid item. The grid library uses row height in order to say how large (y-axis) the charts are - so imagine if the row height is statically set to 100px, then the gird is going to be a width x 400px grid.
The problem comes in because being made for different displays or accounting for if someone is going to have the application minimized (not full screen) the height of the component the charts will be rendered in is variable. I am able to get the height of the component's <div /> by using:
return (
<div
className="content absolute top right left bottom"
ref={divElement => this.divElement = divElement}
>
...
and then calling setState in the componentDidMount lifecycle method.
componentDidMount() {
const height = this.divElement.clientHeight
this.setState({ height })
}
I can get the height of the <div /> fine with this approach but the obvious caveat to this aside from eslint complaining is that it will cause a re-render of the component which is bad.
My question is how should I approach this if there is a better way to complete this same task? Is there another lifecycle method this would be better in (not really thinking there is). It's just that I have to wait until the <div /> the charts reside in to be rendered before I can say how big the charts should be

Related

Imitate 1920x1080 window in a smaller div with sizing of elements

I am working on a project that uses two windows, similar to a video board, where the main screen is a control panel of sorts with a "preview" screen, and the secondary screen is a projection of the viewing content in 1920x1080 resolution. I would like the smaller control panel preview div to match the stylings of the larger viewing window. Currently, I am passing in a "windowInstance" prop to my styled component and adjusting the styles that way, for example:
const SomeComponent = styled.div`
height: ${props => props.windowInstance === 'controlPanel' ? '300px' : '400px'};
`
// ...
return (
<SomeComponent windowInstance={windowInstance} />
)
(windowInstance is passed from the parent component. this is not relevant for the problem at hand, and it gets a bit complicated)
Obviously, this has gotten quite tedious as my app has grown, and nothing is quite right unless I meticulously calculate the difference in window sizes as a percentage and translate that to the new property values. What I want to know is if there is any way with CSS or JS that I can unify these styles and have the results render correctly and identically on both screens.
Important to note is that neither window needs to be responsive or will ever be resized. Here is a sketch I did in excalidraw to better describe the goal:
I was able to solve my problem using the css property zoom - which I was previously unaware of. It works like a charm. My preview screen happens to be exactly 47.5% of the size of my viewing window. So I solved the problem like this:
// Wrapper.js
return (
<StyledWrapper className={windowInstance === 'controlPanel' && 'preview-screen'}>
{children}
</StyledWrapper>
)
// index.css
.preview-screen {
zoom: 47.5%;
}

How can re-render react-grid-layout column's width on parent's resizing?

I have a dashboard panel using react js that I used react-grid-layout in it; I used react-grid-layout in my content and that works correctly but when I close my right side or left side panels (drawers) , the width of my content that is the parent of my react-grid-layout modifies but after this changes my column's width did not modify according to their parent's width size; How can I reload my ResponsiveGridLayout component to changing the childs(columns) width?
this is simple code for showing my problem in this question :
example
this is my dashboard image :
If you look at the documentation here you'll see that ResponsiveGridLayout is a combination of a component called Responsive and a HOC called WidthProvider
import { Responsive, WidthProvider } from 'react-grid-layout';
const ResponsiveGridLayout = WidthProvider(Responsive);
If you look at the code of WidthProvider you may notice it subscribes to widnow resize event
window.addEventListener("resize", this.onWindowResize);
which isn't particularly useful for you, because in your case window does not resize. One way to deal with this problem is to create your own WidthProvider and attach the listener to the element that actually resizes and wrap it around Responsive
const MyVeryOwnResponsiveGridLayout = MyWidthProvider(Responsive);
P.S. You can try requesting the feature from the component creator or volunteer to contribute to the project
I found a better answer than extending the WidthProvider:
Trigger a Window Resize event (without actually resizing the window). I found a delay of 1ms is necessary to make it work.
See this solution:
https://stackoverflow.com/a/62874552/17570516

Dynamic pageSize property of the Ant Design's Table

I'm using Ant Design to get a data Table with pagination. My desired result is to have this component stretched over the entire height of a parent container and adjust the number of rows according to the available space. But, since I have to think about different end users' screen sizes I can't simply assume how many rows would be there in a single page, like this:
<Table
pagination={{ pageSize: 6 }}
columns={columns}
dataSource={sampleData}
/>
Is there any recommended approach to make the pageSize property react to a screen's height changes dynamically? Or should I just set certain breakpoints manually?
There is no antd API for such behavior, you need to calculate it by yourself.
Useful functions to determine the screen height are:
clientHeight
getBoundingClientRect
Notice that those element functions, in React you should access them via a reference, for example with useRef.
The way I solve this UX problem is by to set the scroll property:
scroll={{ y: "calc(100vh - 250px)" }}
With this, the height of the Table will adapt to the user's client height, you'll just need to change 250px to whatever works for you.

Forcing a single re-render to measure DOM elements?

I'm developing a numerical Slider component in React. It actually works right now and is fully functional, but there is a single issue. I set the width of the thumb and total slider via CSS, and I like doing it that way, as it's flexible.
The slider and thumb width is also needed for calculations, such as calculating the max position of the slider, or the position of the thumb relative to the absolute.
So, I have functions like this:
getSliderWidth = () => {
return this.sliderRef.current ? this.sliderRef.current.offsetWidth : 0;
}
getThumbWidth = () => {
return this.sliderThumbRef.current ? this.sliderThumbRef.current.clientWidth : 0;
}
Where the refs are defined in the render function like so:
<div ref={this.sliderRef} className="slider-range">
<div className="slider-range-connect" style={connectStyle}></div>
<div ref={this.sliderThumbRef} className="slider-range-thumb" style={thumbStyle}></div>
</div>
The issue with this, though, is that the widths are only known after the first render. The refs aren't available until it is first rendered. So, I think what I need to do is force a re-render, such that when the component is initially loaded, it is rendered one more time. This is because the initial render function needs to know the relative max position and thumb position in order to render the initial elements.
So, is there a "React" way to do this, or am I missing something? Is the ideal solution here to have some sort of boolean flag, and in the initial mount function, to check this flag, and if it is the first render, to do another render, and then to set the flag? That doesn't seem very "React"ish, so I was wondering if there is something more elegant.

Dynamic bootstrap nav wrapping menu items

I have a Bootstrap 3.3.7 page with a navbar component along the top of the page. It all works perfectly when populated with static data, but when I'm trying to populate the menu with new drop down lists based on some ajax loads from the server the menu line wraps even though there is loads of horizontal space.
I assume it is setting some fixed width based on the initial menu, and then failing to cope with the dynamic widening. If I manually narrow the page the point the nav collapses, and then widen it again then the reflow catches up and it all ends up back on one line.
Is there any way to force the Bootstrap nav to reflow programatically?
The specific element I need to make wider is ".navbar-right", and if I hand code CSS to make it wider after the dynamic addition then this works, but I'd rather not hard-code arbitrary constants into the code given that the menus are not constant and the font may change.
Answering my own question (although would appreciate any better alternatives if anyone knows any) - this seems to work OK.
// Perform the dynamic update
var htmlOutput = $.render.mytemplate(params);
$("#mynavtemplate").replaceWith(htmlOutput);
// Measure the total width of the children of .navbar-right
var newWidth = 0;
$(".navbar-right").children().each(function(){ newWidth += $(this).width(); });
// Force .navbar-right to be at least as wide as the sum of children
$(".navbar-right").css("min-width", newWidth);

Categories

Resources