React-window: 使用react-window反应自定义滚动条

创建于 2018-12-17  ·  35评论  ·  资料来源: bvaughn/react-window

我正在使用react-custom-scrollbar并希望将其与FixedSizeList集成。

我已经在react-virtualized上检查了关于此问题的解决方案: https :

但是代码在此函数中抛出错误: Uncaught TypeError: Cannot read property 'handleScrollEvent' of undefined滚动显示:

  handleScroll = ({ target }) => {
    const { scrollTop, scrollLeft } = target;

    const { Grid: grid } = this.List;

    grid.handleScrollEvent({ scrollTop, scrollLeft });
  }

我在fixedSixe <List组件上添加了ref={ instance => { this.List = instance; } }

💬 question

最有用的评论

更好的方法是将Scrollbars作为outerElementType

const CustomScrollbars = ({ onScroll, forwardedRef, style, children }) => {
  const refSetter = useCallback(scrollbarsRef => {
    if (scrollbarsRef) {
      forwardedRef(scrollbarsRef.view);
    } else {
      forwardedRef(null);
    }
  }, []);

  return (
    <Scrollbars
      ref={refSetter}
      style={{ ...style, overflow: "hidden" }}
      onScroll={onScroll}
    >
      {children}
    </Scrollbars>
  );
};

const CustomScrollbarsVirtualList = React.forwardRef((props, ref) => (
  <CustomScrollbars {...props} forwardedRef={ref} />
));

// ...

<FixedSizeList
  outerElementType={CustomScrollbarsVirtualList}
  {...rest}
/>

示例https://codesandbox.io/s/vmr1l0p463

所有35条评论

该库和react-virtualized是完全不同的实现。 您在react-virtualized问题上看到的一般技术通常可以提供有关如何处理某事的有用提示,但是像这样的特定实现细节不适用。 (在react-virtualizedList装饰Grid组件。在react-window它们是独立的组件,以提高性能和尺寸。)

我不知道像react-custom-scrollbar是否可以与react-window因为我从未尝试过。 说实话,这并不是我很感兴趣的支持,因为我认为自定义滚动条通常是一个坏主意,因为它们会影响性能。 所以我要解决这个问题。

但是,如果您有后续问题,我们可以继续聊天😄

我会对此有所了解,我对使用react-window感兴趣,因为它是轻量级的,可以解决我的问题。 即使我不喜欢使用自定义滚动条,但它不在我手中,我们需要滚动条的自定义设计。

在最坏的情况下,我将使用react-virtualized
谢谢 :)

@ Rahul-Sagore最后是否获得了与react-window一起使用的自定义滚动条?

不,没有时间。 需要检查并弄清楚。

不知道@bvaughn是否批准了此方法,但它似乎可以工作: https : //codesandbox.io/s/00nw2w1jv

更好的方法是将Scrollbars作为outerElementType

const CustomScrollbars = ({ onScroll, forwardedRef, style, children }) => {
  const refSetter = useCallback(scrollbarsRef => {
    if (scrollbarsRef) {
      forwardedRef(scrollbarsRef.view);
    } else {
      forwardedRef(null);
    }
  }, []);

  return (
    <Scrollbars
      ref={refSetter}
      style={{ ...style, overflow: "hidden" }}
      onScroll={onScroll}
    >
      {children}
    </Scrollbars>
  );
};

const CustomScrollbarsVirtualList = React.forwardRef((props, ref) => (
  <CustomScrollbars {...props} forwardedRef={ref} />
));

// ...

<FixedSizeList
  outerElementType={CustomScrollbarsVirtualList}
  {...rest}
/>

示例https://codesandbox.io/s/vmr1l0p463

我喜欢使用outerElementTypeinnerElementType可以进行多少高级操作

我正在尝试检测react-window底部的滚动位置。
是否可以? 您对此有什么想法吗? 我想要一个codeandbox示例。

您应该能够使用可用的ref道具向列表询问其scrollHeight @rufoot。

我尝试在道具中使用scrollHeight 。 但我认为其中没有scrollHeight属性。
@bvaughn

https://codesandbox.io/s/github/bvaughn/react-window/tree/master/website/sandboxes/scrolling-to-a-list-item

scrollToRow200Auto = () => { this.listRef.current.scrollToItem(200); console.log("current position = ", this.listRef.current.props.scrollHeight) };

当前位置=未定义

@rufoot这样的东西https://codesandbox.io/s/4zjwwq98j4吗?

https://codesandbox.io/embed/jzo2lool2y

当您向下滚动到反应窗口的底部时,您会看到一个警报。

@piecyk我已经用outerElementType尝试了您的解决方案,但它太慢了,您是否经过了实战测试?:D

我已经尝试过react-scrollbars-custom 。 它不那么迟钝,但仍然很迟钝。 有人使用自定义滚动条有滞后问题吗?

@ jancama2尚未对它进行战斗测试😂当代码沙箱变得懒惰时,您可以共享它吗?

@rufoot这样的东西https://codesandbox.io/s/4zjwwq98j4吗?

我正在使用您的实现,但收到一条错误消息,指出forwardedRef不是函数。

我要解决的应用程序中的问题是,我有很多项,当我单击一个项目时,该应用程序将重定向到另一条路线,因此我需要跟踪滚动位置(可能在redux中),并且然后在更改路线后设置滚动位置。

@piecyk您是否尝试过将其与react-window-infinite-loader的InfiniteLoader结合使用。
我正在使用react-scrollbars-custom ,它似乎正在打破无限加载器:(

我的代码:

<InfiniteLoader isItemLoaded={isItemLoaded} itemCount={items.total} loadMoreItems={loadMoreItems}>
      {({
        onItemsRendered,
        ref,
      }: {
        onItemsRendered: (props: ListOnItemsRenderedProps) => any;
        ref: React.Ref<any>;
      }) => (
        <List
          height={TABLE_HEIGHT}
          width={width}
          itemCount={items.total}
          itemSize={ROW_HEIGHT}
          onItemsRendered={onItemsRendered}
          itemData={{ items }}
          ref={ref}
          outerElementType={Scrollbar}
        >
          {Row}
        </List>
      )}
    </InfiniteLoader>

更新:我不认为它与无限滚动组件有关。 我无法使其与自定义滚动条一起使用。

如果有人可以与我共享react-scrollbars-custom的实现,我将不胜感激

@ranihorev是否需要使用该软件包? 上面共享的代码笔@piecyk使用react-custom-scrollbars并运行良好(创建引用时除外,由于某种原因,该引用在我的代码中为null)

好的,我需要再问一遍。 @piecyk我正在从上面使用代码示例(在这里您回复了@simjes )。 我没有使用固定大小的列表,而是使用自动大小调整器来包装VariableSizeList并指定externalElementType。 像这样的东西:
<TreeRoot onDragOver={e => this.onDragOver(e)} > <AutoSizer> {({ height, width }) => ( <List treeRef={this.props.treeRef} width={width} height={height} itemSize={index => rowHeights[index]} itemCount={nodeTree.length} itemData={{ nodeTree, expandedNodes, nodesFetching, nodesFetchingFailed, selectedNode, selectedNodeId, resetRowHeight: this.resetRowHeight, }} outerElementType={TreeScrollbar} outerRef={this.props.outerRef} onScroll={({ scrollOffset, scrollUpdateWasRequested }) => { if (scrollUpdateWasRequested) { console.log('scrollOffset: ', scrollOffset); } }} > {Node} </List> )} </AutoSizer> </TreeRoot>

我以与您相同的方式实现CustomScrollbars和CustomScrollbarsVirtualList,但是ref始终为null。 我尝试在正在使用AutoSizer的组件以及它的父组件中创建引用,但是它始终为null。 我真的很感谢能帮助理解原因。 如上所述,我需要跟踪滚动位置并能够在应用程序的路线更改中对其进行设置,以便列表不会跳回到顶部。

@ChristopherHButler我已经在代码中多次使用了该程序包,因此我宁愿继续使用相同的程序包。 我的解决方案非常相似,但是它不会ptoperly获取新数据

如果没有该问题的任何代码沙箱示例,
这里的基本思想是从react-custom-scrollbars设置ref,以便react-window

在此示例中,AutoSizer或VariableSizeList将使用此方法
https://codesandbox.io/s/react-window-custom-scrollbars-t4352

@ranihorev您还可以分享代码沙箱示例吗?

@piecyk我创建了一个简单的示例(已损坏):
https://codesandbox.io/s/bvaughnreact-window-fixed-size-list-vertical-64kzh?fontsize=14

我还尝试了其他变体(例如,将ref设置为滚动包装器),但没有成功...

谢谢!

无论自定义滚动实现如何, @ ranihorev的方法都是相同的。 他们需要设置对负责滚动并处理该滚动事件的同一元素的引用。

react-scrollbars-custom使用渲染道具模式提供了更好的api,因此您可以执行类似https://codesandbox.io/s/bvaughnreact-window-react-scrollbars-custom-pjyxs的操作

没有做任何分析,希望对您有帮助👍

@piecyk我在这里与您的演示一起工作: https : //codesandbox.io/s/4zjwwq98j4 。 我想使用onScrollStop在redux中调度一个动作,因此我可以设置滚动位置(此线程的一个想法: https :

@ChristopherHButler我认为您最好的选择是使用上下文传递道具,例如

https://codesandbox.io/s/bvaughnreact-window-fixed-size-list-vertical-v2-usi1m

-编辑
如果在路由更改时卸载整个列表,则可以调度操作,最后的scrollOffset可以存储在ref上,并使用VariableSizeList中的onScroll: function在每次滚动更改时进行更新,那么您无需将道具传递给Scrollbars

@piecyk太棒了,谢谢!
顺便说一句,似乎您所需要的只是onScroll函数(我错过了),根本不需要转发ref。
https://codesandbox.io/s/bvaughnreact-window-react-scrollbars-custom-99dn1

@piecyk对不起,我应该提到我的VariableSizeList的实现包装在AutoSizer中,而呈现它的组件是基于类的组件,因此我不确定我可以使用上下文。 也许这就是为什么我无法在onScrollStop上正常工作的原因?

快速更新:
我添加了组件状态并将其设置为onScroll。

`
类BaseTree扩展了Component {
...
状态= {scrollPosition:0,};
...
listRef = React.createRef();
externalRef = React.createRef();
...
使成为 {
const {节点,nodesFetching,nodesFetchingFailed,expandedNodes,selectedNode} = this.props;
返回 (

{({高度,宽度})=>(
ref = {this.listRef}
className =“列表”
outsideRef = {this.outerRef}
outsideElementType = {TreeScrollbar}
宽度= {宽度}
身高= {身高}
onScroll = {{{scrollOffset})=> this.setState({scrollPosition:scrollOffset})}
itemSize = {index => rowHeights [index]}
itemCount = {nodeTree.length}
itemData = {{
nodeTree,
expandNodes,
nodesFetching,
nodesFetchingFailed,
selectedNode,
selectedNodeId,
resetRowHeight:this.resetRowHeight,
}}
>
{节点}

)}

);
}}

const mapStateToProps =状态=>({
scrollPosition:selectors.getTreeScrollPosition(state),
});

const mapDispatchToProps = dispatch =>({
setTreeScrollPosition:位置=> dispatch(actions.setTreeScrollPosition({位置})),
});

导出默认的connect(mapStateToProps,mapDispatchToProps)(BaseTree);
`

然后在componentWillUnmout上,我分派操作以在redux中设置位置,如下所示:

componentWillUnmount() { this.props.setTreeScrollPosition(this.state.scrollPosition); }

我现在唯一的问题是能够在重新安装组件时设置滚动位置。 我试图像这样访问this.listRef上的scrollTop方法:

this.listRef.current.scrollTop()但出现错误,它不是函数。 我不确定我可以使用哪个属性(this.listRef或this.outerRef)来设置滚动位置或使用哪种方法。 我以为可以在BaseTree的componentDidMount中设置它,如下所示:
componentDidMount() { const { scrollPosition } = this.props; if (this.listRef.current) { // console.log('initializing scroll position to : ', scrollPosition); this.listRef.current.scrollTop(scrollPosition); } }
任何帮助使这项工作将不胜感激!
编辑:非常抱歉,但是我的代码在此编辑器中似乎未正确格式化,因此我为此表示歉意:(

@ranihorev forward ref可以像scrollTo, scrollToItem这样的功能来响应窗口

@ChristopherHButler上下文应该与从文档中构建的内容完全一样

上下文提供了一种通过组件树传递数据的方法,而不必在每个级别手动传递道具。

但是,是的,如前所述,如果您在更改路线时卸下整个组件,则无需传递道具。 不会在状态下存储scrollPosition ,因为在滚动发生时您不需要它,减少重新渲染,将其存储在ref上。

onScroll={({ scrollOffset }) => this.setState({ scrollPosition: scrollOffset })}

// to 

lastScrollOffsetRef = React.createRef(0);

<List
  onScroll={({ scrollOffset }) => {
    this.lastScrollOffsetRef.current = scrollOffset
  }}
  // ...rest
/>

// then in 
componentWillUnmount() { 
  this.props.setTreeScrollPosition(this.lastScrollOffsetRef.current); 
}

关于outerRef ,在您的情况下不需要。 listRef.current.scrollTo是您要使用的正确方法。 嗯,您想在componentDidMount调用方法的想法是正确的,应该可以,

https://codesandbox.io/s/bvaughnreact-window-fixed-size-list-vertical-80zo7

似乎在设置引用时出现一些计时问题,可能是AutoSizer延迟了List的渲染,从而使this.listRef.current不确定,

hacky选项是,使用setTimeout打破反应生命周期,并在下一个刻度上调用ref

componentDidMount() {
  window.setTimeout(() => {
    if (this.listRef.current) {
      this.listRef.current.scrollTo(this.props.scrollPosition);
    }
  }, 0);
}

@piecyk非常感谢您的帮助,我真的很感激:)

谢谢@piecyk似乎可行。 更改路线后,安装时会出现一点闪烁,但我可以忍受它:)我还尝试了另一种方法,即使用className传递scrollPosition并在CustomScrollbars的refSetter中设置scrollTop:
if (scrollbarsRef) { forwardedRef(scrollbarsRef.view); // HACK scrollbarsRef.scrollTop(className); }
看来运作良好。
再次感谢您的所有帮助,不胜感激!! 🙌🏻

不幸的是,此问题中的所有示例均无法正常工作(有时鼠标停止响应滚动)。

但是这个例子做得很完美!

无论自定义滚动实现如何, @ ranihorev的方法都是相同的。 他们需要设置对负责滚动并处理该滚动事件的同一元素的引用。

react-scrollbars-custom使用渲染道具模式提供了更好的api,因此您可以执行类似https://codesandbox.io/s/bvaughnreact-window-react-scrollbars-custom-pjyxs的操作

我已经尝试过react-scrollbars-custom 。 它不那么迟钝,但仍然很迟钝。 有人使用自定义滚动条有滞后问题吗?

完成了吗? 最终的解决方案是什么?

如果这对任何人有帮助,我都可以使其与OverlayScrollbars一起

const Overflow = ({ children, onScroll }) => {
  const ofRef = useRef(null);

  useEffect(() => {
    const el = ofRef.current.osInstance().getElements().viewport;

    if (onScroll) el.addEventListener('scroll', onScroll);

    return () => {
      if (onScroll) el.removeEventListener('scroll', onScroll);
    };
  }, [onScroll]);

  return (
    <OverlayScrollbarsComponent
      options={options}
      ref={ofRef}
    >
      {children}
    </OverlayScrollbarsComponent>
  );
};

然后,在您的虚拟化组件中:

<FixedSizeGrid
  {...props}
   outerElementType={Overflow}
>

我将它与FixedSizeGrid但对于列表它应该起作用。

希望能帮助到你。

此页面是否有帮助?
0 / 5 - 0 等级