【问题标题】:How can I use React hooks to respond to a prop change before render如何在渲染之前使用 React 钩子响应道具更改
【发布时间】:2019-08-30 16:39:49
【问题描述】:

我正在尝试使用功能组件和 React 钩子来实现一个简化的自动滚动器,当子内容溢出时,它会自动将容器滚动到底部。但是自动滚动应该只在滚动条已经在底部时发生(例如,如果用户向上滚动查看输出,当新内容进入时滚动位置不应该改变)。

我知道如何通过使用 refs 并在 clientHeight、scrollTop 和 scrollHeight 上执行计算来实现自动滚动行为。

我遇到的问题是我需要在重新渲染组件之前计算shouldAutoScroll() 检查。

我的流程需要如下所示:

<container>
   {props.children}
</container>

When props.children changes:
   1. Check if the scrollbar is near the bottom and store the result
   2. Update container to reflect the new props.children
   3. If the check from step 1 is true, scroll to the bottom

我似乎找不到使用useEffect 和/或useLayoutEffec 的方法。使用这些时会发生什么:

   1. Scroll position is at bottom
   2. props.children updates with new items
   3. <container> is rerendered, pushing the scrollbar up
   4. The checkScrollBarBottom() method is called and returns false
   5. The scrollbar is not auto-scrolled

我需要保持组件的通用性,这样无论 props.children 是什么类型的组件或元素,它都可以自动滚动。在某些情况下,对 props.chldren 的更改可能是一行。在其他情况下,它可能是 20 行,或者它可能是一个图像。

如果我使用的是旧式类组件,我可以在 componentWillReceiveProps() 中进行计算。如何用钩子复制它?

【问题讨论】:

标签: javascript reactjs react-hooks


【解决方案1】:

我发现了一个可行的解决方案,但似乎有点混乱。

解决方案是在容器的onScroll() 事件期间计算并更新shouldAutoScroll()。这看起来很混乱,因为我正在捕获大量无用的中间滚动信息,而我只关心更新开始时的滚动位置(但在重新渲染组件之前)。

完整代码:

import React, { useRef, useEffect, useLayoutEffect } from 'react';
import styles from './AutoScroller.module.scss';

export function AutoScroller({children, className=''}) {
  const classNames = `${styles.default} ${className}`;

  const containerRef = useRef(null);
  const shouldAutoScroll = useRef(false);

  function updateShouldAutoScroll(element, tolerance) {
    const {scrollHeight, scrollTop, clientHeight} = element;
    const result = scrollHeight - scrollTop <= clientHeight + tolerance;

    shouldAutoScroll.current = result;
  }

  function onContainerScroll(e) {
    updateShouldAutoScroll(e.target, 25)
  }

  useEffect(function autoScroll() {
    if (shouldAutoScroll.current) {
      const element = containerRef.current;
      element.scrollTop = element.scrollHeight;
    }
  });

  return (
    <div className={classNames} ref={containerRef} onScroll={onContainerScroll}>
      {children}
    </div>
  )
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-08-23
    • 2021-04-26
    • 2020-06-20
    • 2021-01-06
    • 2023-04-01
    • 2022-12-03
    • 1970-01-01
    • 2023-02-23
    相关资源
    最近更新 更多