简体   繁体   English

如何在 window 调整大小时更新 useRef 挂钩的值

[英]How to update the value of useRef hook on window resize

I have a table component that has a fixed first column when scrolling horizontally.我有一个表格组件,它在水平滚动时具有固定的第一列。 I do this by positioning it absolutely.我通过绝对定位来做到这一点。 This cause a problem.这会导致问题。

When the window is resized, the contents of the table cells may wrap and cause the cells to resize also in height.当 window 调整大小时,表格单元格的内容可能会换行并导致单元格的高度也调整大小。 I have set up a ref for the table component, so that I can fetch the row heights via javascript and resize the absolutely positioned fixed cells accordingly.我已经为表格组件设置了一个参考,这样我就可以通过 javascript 获取行高,并相应地调整绝对定位的固定单元格的大小。

Here's the code:这是代码:

  const NewStatsTable = ({ headers, stats, data, dataType }) => {
  const [cellHeights, setCellHeights] = useState([])
  const tableRef = useRef(null)

  useLayoutEffect(() => {
    handleCellHeightResize()
    window.addEventListener('resize', handleCellHeightResize)
    return window.removeEventListener('resize', handleCellHeightResize)
  }, [])

  const headersToUse = getHeaders(dataType)

  const getData = (item, header) => {
    if (header === 'gameDate') return formatDate(item[headersToUse[header].id])
    return item[headersToUse[header].id]
  }

  const getTallestCellHeights = () => {
    const rows = Array.from(tableRef.current.getElementsByTagName('tr'))

    return rows.map(row => {
      const fixedCell = row.childNodes[0]
      return Math.max(row.clientHeight, fixedCell.clientHeight)
    })
  }

  const handleCellHeightResize = () => {
    setCellHeights(getTallestCellHeights)
  }

  const headerMarkup = () => (
    <TableRow header>{headers.map(renderHeaderRow)}</TableRow>
  )

  const renderHeaderRow = (header, colIndex) => {
    const text = headersToUse[header].headerText
    const height = cellHeights[0]

    return (
      <TCell
        key={header}
        type='th'
        data={text}
        colIndex={colIndex}
        cellHeight={height}
      />
    )
  }

  const cellMarkup = () =>
    data.map((row, rowIndex) => (
      <TableRow key={row._id}>
        {headers.map((header, colIndex) =>
          renderRow(header, row, rowIndex, colIndex)
        )}
      </TableRow>
    ))

  const renderRow = (header, row, rowIndex, colIndex) => {
    const text = getData(row, header)
    const height = cellHeights[rowIndex + 1]

    return (
      <TCell
        key={header}
        type='td'
        data={text}
        colIndex={colIndex}
        cellHeight={height}
      />
    )
  }

  return (
    <Container>
      <ScrollContainer>
        <Table ref={tableRef}>
          <TableHead>{headerMarkup()}</TableHead>
          <TableBody>{cellMarkup()}</TableBody>
        </Table>
      </ScrollContainer>
    </Container>
  )
}

The code works, but it doesn't work on resize, it works only when the page is first loaded.该代码有效,但不适用于调整大小,仅在首次加载页面时有效。 If the window is narrow enough, the higher cell height is calculated correctly.如果 window 足够窄,则可以正确计算较高的单元高度。 The same of course when the window is wide and there is no text wrap in the cells.当然,当 window 很宽并且单元格中没有文本换行时也是如此。

When I resize the window, the row height don't get recalculated.当我调整 window 的大小时,不会重新计算行高。 I suppose this is because the tableRef is created at page load and it doesn't even if the page is resized.我想这是因为tableRef是在页面加载时创建的,即使页面调整大小也不会。

I tried adding an event listener for resize event, but it doesn't help.我尝试为resize事件添加事件侦听器,但没有帮助。 getTallestCellHeights still uses the old ref for the calculation. getTallestCellHeights仍然使用旧的ref进行计算。

How can I update the tableRef so that getTallestCellHeights uses the correct heights for its calculations?如何更新tableRef以便getTallestCellHeights使用正确的高度进行计算?

I think the issue here is the calculation of height.我认为这里的问题是高度的计算。 You are using clientHeight which excludes margin .您正在使用不包括 marginclientHeight As the page is being resized, the computed height is changing, and probably has some media queries that update the margin.随着页面大小的调整,计算出的高度也在变化,并且可能有一些媒体查询会更新边距。

useRef is probably working as expected, but your calculation is not factoring in all values for the element height. useRef可能按预期工作,但您的计算并未考虑元素高度的所有值。

Consider the function in the snippet below:考虑下面代码段中的 function:

  function calcHeight(el) {
      const styles = window.getComputedStyle(el);
      const margin =
        parseFloat(styles["marginTop"]) + parseFloat(styles["marginBottom"]);

      console.log(`trueHeight: ${Math.ceil(el.offsetHeight + margin)}`, `clientHeight: ${el.clientHeight}`);

      return Math.ceil(el.offsetHeight + margin);
    }

You will see the the actual heights vary.您会看到实际高度有所不同。

 function calcHeight(el) { const styles = window.getComputedStyle(el); const margin = parseFloat(styles["marginTop"]) + parseFloat(styles["marginBottom"]); console.log(`trueHeight: ${Math.ceil(el.offsetHeight + margin)}`, `clientHeight: ${el.clientHeight}`); return Math.ceil(el.offsetHeight + margin); } const demo = document.querySelector('.demo'); function onResize(e) { calcHeight(demo); } window.addEventListener("resize", onResize); onResize(demo);
 .container { display: flex; justify-content: center; align-items: center; background: black; width: 100vw; height: 100vh; }.demo { background: red; padding: 25px; margin: 25px; border: 1px solid #fff; } @media (min-width: 500px) {.demo { margin: 50px; background: green; } }
 <div class="container"> <div class="demo"> <h1>Some Content</h1> </div> </div>

Basic React Demo on codeandsandbox Codeandsandbox 上的基本 React 演示

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM