在第一次渲染期间从响应式 React 元素获取宽度?

Posted

技术标签:

【中文标题】在第一次渲染期间从响应式 React 元素获取宽度?【英文标题】:Get width from responsive React element during first render? 【发布时间】:2019-11-24 08:32:46 【问题描述】:

我有一个名为 ResultList 的 React 组件,它负责在画廊中展示产品。

但是为了选择每行产品的正确数量,我需要知道我的组件还剩下多少像素,因为还有一些其他逻辑可以确定侧边栏和过滤栏是否会一起出现ResultList 与否。因此,ResultList宽度 是响应式的,并且会发生变化。

我已经构建了这段代码来获取元素的宽度,但现在它不适用于第一次渲染。而且我不知道这是否可能,因为该元素尚未创建,ref 尚未分配给任何东西。但是,如果我无法知道元素的宽度,我该如何选择在第一次渲染时显示多少产品?

请看下面的 GIF:

我的ResultList 将是Item2

问题

如何在第一次渲染期间获得Item2 的宽度,如果不可能,我该如何隐藏它,直到我知道它的可用宽度是多少?有没有比window.getComputedStyle 更好的方法来获取响应式元素的宽度?

代码沙盒链接:

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);

【问题讨论】:

【参考方案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>
  );


【讨论】:

window.getComputedStyle(itemRef.current).width 返回带有“px”的值。

以上是关于在第一次渲染期间从响应式 React 元素获取宽度?的主要内容,如果未能解决你的问题,请参考以下文章

React 应用程序上的响应式布局

react-native 获取组件的宽度和高度

计算元素的响应宽度以定义大小

响应式布局的一种实现方案,宽度不一样放置元素数量不一样

React Native - 响应式图像宽度(百分比?)

如何响应 React 中自动调整大小的 DOM 元素的宽度?