I am trying to calculate the height of a component before it is previewed to the user. I found the following method online :
const measureElement = element => {
// Creates the hidden div appended to the document body
const container = document.getElementById('temporal-root')
// Renders the React element into the hidden div
ReactDOM.render(element, container)
// Gets the element size
const height = container.clientHeight
const width = container.clientWidth
return { height, width }
return { height: 0, width: 0 }
}
And this is how I use it:
highlightsMemoized.forEach(section => {
const sectionHeight =
measureElement(
<ComponentSection
section={section}
style={{ width: '350px' }}
/>
).height
})
The problem is that height has always the same value, which is the one of the latest item in the loop. Is there a way to get the correct height pf each item using this approach?
Related
I am using Mui Grid and want to generate fixed size grid elements to fill the screen (both height and width) but I don't know how to do that.
Here is a CodeSandbox link of something basic I am working with. In this example, I hard coded it to render 20 elements. I instead want it to account for the screen size, padding, margin, etc. to programmatically determine how many elements to render. Is this possible?
I'm not sure it's possible using Grid, but with plain JavaScript, you should be able to calculate the number of elements to render to fill a page and an event listener on "resize" to continually calculate the proper number of elements to render to completely fill the page width.
CodeSandbox Example
const itemWidth = 100;
const gridGap = 10;
const Item = styled(Paper)(({ theme }) => ({
textAlign: "center",
width: `${itemWidth}px`,
height: "100px"
}));
export default function ResponsiveGrid() {
const [numOfEl, setNumOfEl] = useState(
Math.floor(window.innerWidth / (itemWidth + gridGap))
);
function getNumberOfElements() {
setNumOfEl(Math.floor(window.innerWidth / (itemWidth + gridGap)));
}
useEffect(() => {
window.addEventListener("resize", getNumberOfElements);
return () => window.removeEventListener("resize", getNumberOfElements);
}, []);
return (
<Grid container sx={{ gap: `${gridGap}px` }}>
{Array.from(Array(numOfEl)).map((_, index) => (
<Grid key={index}>
<Item>{index}</Item>
</Grid>
))}
</Grid>
);
}
Edit: I only calculated the number for the width, but you get the idea.
I want to know the margin-left of div1, so I can use it in my code. Setting it this way, the margin on the left will change depending on the screen size. How can I detect the margin left of this div?
<div class="max-w-6xl m-auto">
</div>
In react, you can make use of the ref callback, which receives the HTML DOM element as an argument. Inside of this callback, you could query the margin-left style from the element and store it in a state. Here's an example:
const App = () => {
const [marginLeft, setMarginLeft] = useState(0); // in pixels
const retrieveMargin = (elm) => {
if (elm != null) {
let styles = window.getComputedStyle(elm);
let ml = styles.getPropertyValue("margin-left");
setMarginLeft(Number.parseInt(ml.replace("px", "")));
}
};
return <div class="mydiv" ref={retrieveMargin}></div>;
};
I'm currently working on a pet web project with react and I'm using a container that's 16:9 and scaling with the current viewport. The idea is based on a pen, I've created with vanilla JS (https://codepen.io/AllBitsEqual/pen/PgMrgm) and that's already working like a charm.
function adjustScreen() {...}
adjustScreen()
[...]
const resizeHandler = function () { adjustScreen() }
window.addEventListener('resize', helpers.debounce(resizeHandler, 250, this))
I've now written a script that's sitting in my App.jsx, (un)binds itself via useEffect and calculates the current size of the viewport to adjust the container, whenever the viewport changes (throttled for performance). I'm also using media queries to adjust the size and font size of elements in the container, which is working ok but isn't much fun to work with.
I want to expand on this idea and change the font size of the HTML Element in the same function that calculated the current container size so that I can use REM to scale font-size and other elements based on my calculated root font size.
Is there a valid and future-proofed way of changing the font-size style of my Tag via ReactJS either via the style tag or style attribute?
For now I've resorted to using "document.documentElement" and "style.fontSize" to achieve what I wanted but I'm not 100% sure this is the best solution. I'll see if I can find or get a better solution before I accept my own answer as the best...
I'm using useState for the game dimensions and within the useEffect, I'm attaching the listener to resize events, which I throttle a bit for performance reasons.
const App = () => {
const game_outerDOMNode = useRef(null)
const rootElement = document.documentElement
function getWindowDimensions() {
const { innerWidth: width, innerHeight: height } = window
return {
width,
height,
}
}
const [gameDimensions, setGameDimensions] = useState({ width: 0, height: 0})
useEffect(() => {
function adjustScreen() {
const game_outer = game_outerDOMNode.current
const ratioHeight = 1 / 1.78
const ratioWidth = 1.78
const { width: vw, height: vh } = getWindowDimensions()
const width = (vw > vh)
? (vh * ratioWidth <= vw)
? (vh * ratioWidth)
: (vw)
: (vh * ratioHeight <= vw)
? (vh * ratioHeight)
: (vw)
const height = (vw > vh)
? (vw * ratioHeight <= vh)
? (vw * ratioHeight)
: (vh)
: (vw * ratioWidth <= vh)
? (vw * ratioWidth)
: (vh)
const longestSide = height > width ? height : width
const fontSize = longestSide/37.5 // my calculated global base size
setGameDimensions({ width, height })
rootElement.style.fontSize = `${fontSize}px`
}
const debouncedResizeHandler = debounce(200, () => {
adjustScreen()
})
adjustScreen()
window.addEventListener('resize', debouncedResizeHandler)
return () => window.removeEventListener('resize', debouncedResizeHandler)
}, [rootElement.style.fontSize])
const { width: gameWidth, height: gameHeight } = gameDimensions
return (
<div
className="game__outer"
ref={game_outerDOMNode}
style={{ width: gameWidth, height: gameHeight }}
>
<div className="game__inner">
{my actual game code}
</div>
</div>
)
}
I'm making a Collapse component using react-spring which receives children and a boolean collapsed prop.
It's rather basic, but for some reason the animation when children are mounted never runs and at the same time leave animation works good.
Here's what the component looks like
const baseStyles = {
overflow: "hidden"
};
const openStyles = {
height: "auto"
};
const collapsedStyles = {
height: 0
};
const animationConfig = {
duration: 1000
};
const Collapse = ({ collapsed, children, ...props }) => {
return (
<Transition
items={collapsed}
native
config={animationConfig}
from={baseStyles}
enter={openStyles}
leave={collapsedStyles}
// onFrame={console.log}
{...props}
>
{collapsed => !collapsed
? style => <animated.div style={style} children={children} />
: null
}
</Transition>
);
};
And here's working code https://codesandbox.io/s/459p84ky4
Am I doing something wrong or is it a bug in react spring?
You need to understand from and enter you are not applying anything in both props, means opacity is always 1 and thus animation is not working
from means what it should be at the initial stage and enter means what it should be at rendering.
So, you need to set opacity 0 in from and set it to 1 inside enter
const baseStyles = {
background: "rgba(255,0,0,.2)",
overflow: "hidden",
opacity:0
};
const openStyles = {
height: "auto",
opacity: 1
};
Edit:
If you want height form zero to auto then you need to first set height to 0 in from
const baseStyles = {
background: "rgba(255,0,0,.2)",
overflow: "hidden",
height: 0
};
const openStyles = {
height: "auto",
opacity: 1
};
Demo
I am trying to measure the height of a component, If i try to get the ref and find the offsetHeight, the ref is returned to be null always. so How to measure the height for a react-semantic-ui component.
<Container ref={rf=>this.container=rf} style={{overflowY:"auto"}}>
<Item.Group divided >
<ItemList items={items}></ItemList>
</Item.Group>
</Container>
here this.container is always null
What other ways are there to measure the height of a react-semantic-ui component ?
#bogdan-surai, can you test the following code:
componentDidMount() {
const container = this.container;
if (!container) {
return;
}
const specs = container.getBoundingClientRect();
console.log(specs);
}
#salman.zare Yep. It doesn't work when componentDidMount just have fired. I guess the cause is height really equals 0 at that moment. But we can run setInterval to get height in few time later.
This code works for me
componentDidMount() {
this.intervalId = setInterval(() => {
const container = this.container;
if (!container) {
return;
}
const specs = container.getBoundingClientRect();
console.log(specs);
console.log(this.scrollComponent.offsetHeight);
this.setState(() => ({ height: specs.height }));
}, 100);
}
Then I see it in the browser's console.
DOMRect {x: 0, y: 120, width: 693, height: 0, top: 120, …}
DOMRect {x: 0, y: 16, width: 678, height: 4068, top: 16, …}
You should use this.container.offsetHeight in componentDidMount or componentDidUpdate methods.
It is possible to wrap your components into <div ref={...}></div>. Then you can get height of the div. If your higher component doesn't have margins, height of div and your component will be the same.
Note:
When the ref attribute is used on a custom component declared as a class, the ref callback receives the mounted instance of the component as its argument.
When the ref attribute is used on an HTML element, the ref callback receives the underlying DOM element as its argument.
You may not use the ref attribute on functional components because they don’t have instances
Returned values from 1 and 2 have different properties and methods. There is a doc https://reactjs.org/docs/refs-and-the-dom.html