我有一个名为ResultList
的React组件,负责在画廊中展示产品。
但是为了选择正确的每行产品数量,我需要知道要为组件剩余多少像素,因为还有其他逻辑可以确定边栏和过滤器栏是否会与是否ResultList
。因此,ResultList
的 width 是自适应的,并且有所不同。
我已经构建了这段代码来获取元素的宽度,但是现在它不适用于第一个渲染。而且我不知道这是否可能,因为尚未创建元素并且ref
尚未分配任何内容。但是,如果我不知道元素的宽度,该如何选择在第一次渲染中显示多少个产品?
请参阅下面的GIF:
我的ResultList
是Item2
问题
如何在第一次渲染期间获得Item2
的宽度,如果不可能的话,如何隐藏它,直到我知道它的可用宽度是多少?是否有比window.getComputedStyle
更好的方法来获得响应元素的宽度?
CodeSandbox链接:
https://codesandbox.io/s/wizardly-blackburn-f1p7j
完整代码:
import React, { useRef, useState } from "react";
import ReactDOM from "react-dom";
import styled from "styled-components";
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);
答案 0 :(得分:1)
要等到元素渲染完毕后,ref才具有值,您将需要使用效果。 useEffect之类的作品,但是在重新计算之前,您会看到它呈现一次闪烁。而是在这种情况下可以使用useLayoutEffect。它将渲染一次,然后进行测量并设置状态,然后再次同步渲染,因此不应出现闪烁。
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>
);
}