How get the horizontal-size from the DOM? - javascript

I have a complex web page using React components, and am trying to convert the page from a static layout to a more responsive, resizable layout. However, I keep running into limitations with React, and am wondering if there's a standard pattern for handling these issues. In my specific case, I have a component that renders as a div with display:table-cell and width:auto.
Unfortunately, I cannot query with width of my component, because you can't compute the size of an element unless it's actually placed in the DOM (which has the full context with which to deduce the actual rendered width). Besides using this for things like relative mouse positioning, I also need this to properly set width attributes on SVG elements within the component.
In addition, when the window resizes, how do I communicate size changes from one component to another during setup? We're doing all of our 3rd-party SVG rendering in shouldComponentUpdate, but you cannot set state or properties on yourself or other child components within that method.
Is there a standard way of dealing with this problem using React?

The method of lifecycle you probably want is componentDidMount
The elements have already been placed in the DOM and you can get information about them from the component's refs.
Example:
var Container = React.createComponent({
componentDidMount: function () {
var width = this.refs.svg.getDOMNode().offsetWidth;
},
render: function () {
<svg ref="svg" />
}
});

In componentDidMount you can get the window.width or ReactDom.findDOMNode(this).width. Then use the width in state and pass as a prop as needed. You can also set a listener for the resize event.

Related

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

React: How to get the ref height of an element coming from the children with dynamic height?

I have a component that has some element with text.
Based on some other stuff the text can be some words or can be a wall of text. From the parent I need to know the exact height at any time of the element inside of the children
I have tried using callback refs but to no avails. I can only get the first value but then I need it to update
https://codesandbox.io/s/nervous-mendeleev-xf2cg?file=/src/App.js
Here is an example of the code.
Update: one thing that I notice when I check directly the height is that I get the previous value (kinda like when you use setState and dont realize it is asynchronous)
when small ( height: ~60) it shows ~100
when big the other way around
one thing that I notice when I check directly the height is that I get
the previous value
You can still salvage this solution. It is getting the previous value because you are checking for the height right away but the issue is that the component is not done rendering using the new words (i.e., the ref height would still return the previous height).
What you can do is to leverage useEffect. When the component is done rendering (equivalent of this in class implementation is componentDidUpdate), that is when you start checking its height.
useEffect(() => {
// the component is done rendering - now you can check for its new height here
}, [words, onClick]);

Fluent UI Reading the height of DetailsList's ViewPort

I'm using DetalisList within ScrollablePane component to keep the header in view, and let the rows scrollable. However, this requires me to manually set the height of the scrollable container.
div.scrollable-container
ScrollablePane
DetailsList
When I investigate the DOM elements for DetalisList, I can see that it's wrapped inside a ViewPort element. The height of this element is the actual height of the sum of the height of all components that make up the list (column headers, rows. etc.). Thus, I want to be able to read this value and set the container height based on whether it exceeds a certain value or not.
Is there a nice to way to access the height of the ViewPort? I can always query the DOM, and find the element, but I'd like to avoid relying on the internal structure of the component.
So, far I could not find any information on this. I noticed DetailsList takes a prop called viewport, but I don't think this is what I want.
You can try by giving height in "vh" (viewport height) unit. For example,
const gridContainerStyle: IStackStyles = {
root: { height: "70vh", position: "relative" },
};

ReactJS - Do not render until component is above page fold (within visible window area)

Scenario
I'm working on a ReactJS project that has a lot of re-used components on the page, so many components that it causes some of the css animations to become sluggish. I've found that if I use display:none on components below the page fold that my performance bottlenecks vanish.
Question
Is there a currently library, or a very simple way to accomplish this? Worst case I will write a library for this and put it on github.
Caveats
Using display:none gives an element 0 width / height so I'll need to use a placeholder of an assumed size.
I will "unrender" visible components once they go out of the visible window area
lazy loading libs didn't pan out like I hoped, LazyLoadJS is the most promising and what I would leverage if I ultimately need to write my own solution
My situation is rather unique but I'll break it down to relevant pieces as much as I can:
My application is a ReactJS SPA or Single Page Application (so lots of xhr, async loading)
Using the same scroll area for the entire life cycle (.content-group)
Json from the CMS includes component names and respective data. My "SomeFactory" (not the real name) gets the mapped component name and renders the component to the factory container.
Some Caveats:
forceCheck is what made this work, it reassess where lazy items are within the scroll container
overflow was helpful since I'm using overflow: hidden as part of this element's ancestry.
Code
import LazyLoad, { forceCheck } from 'react-lazyload';
class LazyLoadOptimized extends React.Component {
render() {
return (
<LazyLoad throttle={50} height={200} offset={400} overflow scrollContainer={'.content-group'}>
{this.props.children}
</LazyLoad>
)
}
}
export default class SomeFactory extends Component {
componentDidUpdate() {
forceCheck();
}
}

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.

Categories

Resources