如何在渲染之前使用 React 钩子来响应道具更改



我正在尝试使用功能组件和 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.kids 是什么类型。在某些情况下,对 props.chldren 的更改可能是一行。在其他情况下,它可能是 20 行,也可能是图像。

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

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

解决方案是在容器的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>
)
}

相关内容

  • 没有找到相关文章

最新更新