我正在尝试使用功能组件和React钩子来实现简化的自动滚动器,当子内容溢出时,该自动滚动器将容器自动滚动到底部。但是,只有在滚动条已经位于底部时,才应进行自动滚动(例如,如果用户向上滚动以查看输出,则当出现新内容时滚动位置不应更改)。
我知道如何通过使用引用并在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()中进行计算。如何用钩子复制它?
答案 0 :(得分:0)
我发现了一个可行的解决方案,但似乎有些混乱。
解决方案是在容器的shouldAutoScroll()
事件期间计算和更新onScroll()
。这似乎很混乱,因为我正在捕获大量无用的中间滚动信息,而我所关心的只是更新开始时(但组件重新呈现之前)的滚动位置。
完整代码:
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>
)
}