I have a React ponent named ResultList
that is responsible for displaying products in a gallery.
But in order to choose the correct quantitity of products per row, I need to know how many pixels were left for my ponent, because there is some other logic that will determine if a side bar and a filter bar will appear together with the ResultList
or not. Hence, the width of ResultList
is responsive and it varies.
I've built this code to get the width of the element, but right now it doesn't work for the first render. And I don't know if that would be possible, because the element hasn't been created yet and the ref
has not been assigned to anything. But how can I choose how many products to display on first render if I'm not able to know how wide my element is going to be?
See GIF below:
my ResultList
would be the Item2
QUESTION
How can I get the width of Item2
during first render, and if that's not possible how can I hide it until I know what is the available width for it? Is there a better way to get the width of a responsive element than with window.getComputedStyle
?
CodeSandbox Link:
Full Code:
import React, { useRef, useState } from "react";
import ReactDOM from "react-dom";
import styled from "styled-ponents";
const S = {};
S.Container_DIV = styled.div`
display: flex;
height: 150px;
`;
S.FlexItem1 = styled.div`
flex: 0 0 200px;
background-color: lightblue;
`;
S.FlexItem2 = styled.div`
flex: 1 1 80%;
background-color: lightcoral;
`;
S.FlexItem3 = styled.div`
flex: 0 0 160px;
background-color: lightgreen;
`;
function App() {
const itemRef = useRef(null);
const [boolean, setBoolean] = useState(false);
return (
<React.Fragment>
<S.Container_DIV>
<S.FlexItem1>Item 1</S.FlexItem1>
<S.FlexItem2 ref={itemRef}>Item 2</S.FlexItem2>
<S.FlexItem3>Item 3</S.FlexItem3>
</S.Container_DIV>
<div>
<br />
Item2 width is:{" "}
{itemRef.current && window.getComputedStyle(itemRef.current).width}
</div>
<div>
<button onClick={() => setBoolean(prevState => !prevState)}>
Force Update
</button>
</div>
</React.Fragment>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
I have a React ponent named ResultList
that is responsible for displaying products in a gallery.
But in order to choose the correct quantitity of products per row, I need to know how many pixels were left for my ponent, because there is some other logic that will determine if a side bar and a filter bar will appear together with the ResultList
or not. Hence, the width of ResultList
is responsive and it varies.
I've built this code to get the width of the element, but right now it doesn't work for the first render. And I don't know if that would be possible, because the element hasn't been created yet and the ref
has not been assigned to anything. But how can I choose how many products to display on first render if I'm not able to know how wide my element is going to be?
See GIF below:
my ResultList
would be the Item2
QUESTION
How can I get the width of Item2
during first render, and if that's not possible how can I hide it until I know what is the available width for it? Is there a better way to get the width of a responsive element than with window.getComputedStyle
?
CodeSandbox Link:
https://codesandbox.io/s/wizardly-blackburn-f1p7j
Full Code:
import React, { useRef, useState } from "react";
import ReactDOM from "react-dom";
import styled from "styled-ponents";
const S = {};
S.Container_DIV = styled.div`
display: flex;
height: 150px;
`;
S.FlexItem1 = styled.div`
flex: 0 0 200px;
background-color: lightblue;
`;
S.FlexItem2 = styled.div`
flex: 1 1 80%;
background-color: lightcoral;
`;
S.FlexItem3 = styled.div`
flex: 0 0 160px;
background-color: lightgreen;
`;
function App() {
const itemRef = useRef(null);
const [boolean, setBoolean] = useState(false);
return (
<React.Fragment>
<S.Container_DIV>
<S.FlexItem1>Item 1</S.FlexItem1>
<S.FlexItem2 ref={itemRef}>Item 2</S.FlexItem2>
<S.FlexItem3>Item 3</S.FlexItem3>
</S.Container_DIV>
<div>
<br />
Item2 width is:{" "}
{itemRef.current && window.getComputedStyle(itemRef.current).width}
</div>
<div>
<button onClick={() => setBoolean(prevState => !prevState)}>
Force Update
</button>
</div>
</React.Fragment>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Share
Improve this question
asked Jul 15, 2019 at 15:42
cbdevelopercbdeveloper
31.6k45 gold badges202 silver badges397 bronze badges
1 Answer
Reset to default 5To wait until the elements have rendered and thus the ref has a value you'll need to use an effect. useEffect kind of works, but you'll see a flicker of it rendering once before you recalculate. Instead, this is a case where useLayoutEffect can be used. It will render once, then you do your measurement and set state, then it will synchronously render again so no flicker should be seen.
function App() {
const itemRef = useRef(null);
const [itemWidth, setItemWidth] = useState(-1);
const [boolean, setBoolean] = useState(false);
useLayoutEffect(() => {
// I don't think it can be null at this point, but better safe than sorry
if (itemRef.current) {
setItemWidth(window.getComputedStyle(itemRef.current).width);
}
});
return (
<React.Fragment>
<S.Container_DIV>
<S.FlexItem1>Item 1</S.FlexItem1>
<S.FlexItem2 ref={itemRef}>Item 2</S.FlexItem2>
<S.FlexItem3>Item 3</S.FlexItem3>
</S.Container_DIV>
<div>
<br />
Item2 width is: {itemWidth}
</div>
<div>
<button onClick={() => setBoolean(prevState => !prevState)}>
Force Update
</button>
</div>
</React.Fragment>
);
}