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

最も参考になるコメント

より良いアプローチは、 ScrollbarsouterElementTypeとして渡すことです。

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-virtualizedでは、 ListGridコンポーネントを装飾します。 react-windowでは、パフォーマンスとサイズを向上させるために、これらは別々のコンポーネントです。)

以下のようなものかどうかは知りませんreact-custom-scrollbarで動作しますreact-window私はそれを試したことがないからです。 カスタムスクロールバーはパフォーマンスにどのように影響するかという理由で一般的に悪い考えだと思うので、正直に言うと私がサポートすることにあまり興味がありません。 だから私はこの問題を閉じるつもりです。

ただし、フォローアップの質問がある場合は、引き続きチャットできます😄

これについて何かを理解します。軽量で問題が解決するため、 react-window使用に興味があります。 カスタムスクロールバーを使用するのは好きではありませんが、手元にはありません。スクロールバーのカスタムデザインが必要です。

最悪の場合、 react-virtualized使用します。
ありがとう:)

@ Rahul-Sagoreは、カスタムスクロールバーをreact-windowか?

いいえ、そのための時間がありませんでした。 チェックして理解する必要があります。

@bvaughnがこれを承認するかどうかはhttps//codesandbox.io/s/00nw2w1jv

より良いアプローチは、 ScrollbarsouterElementTypeとして渡すことです。

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

outerElementTypeまたはinnerElementTypeを使用していくつの高度なことが可能であるかが大好きです

react-windowの下部にあるスクロール位置を検出しようとしています。
出来ますか? そのためのアイデアはありますか? codesandboxの例が

利用可能なrefpropsを使用して、リストに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

react-windowの下部を下にスクロールすると、1つのアラートが表示されます。

@piecyk outerElementTypeあなたの解決策を試しましたが、それは非常に遅れています、あなたはそれをバトルテストしましたか?:D

react-scrollbars-custom試してみました。 ラグは少なくなりますが、それでもラグがあります。 カスタムスクロールバーを使用したラグに問題があったことはありますか?

@ jancama2

@rufootこのようなものhttps://codesandbox.io/s/4zjwwq98j4

私はあなたの実装を使用していますが、forwardedRefが関数ではないというエラーが表示されます。

私が解決しようとしている私のアプリの問題は、アイテムのリストがたくさんあり、1つをクリックすると、アプリが別のルートにリダイレクトされるため、スクロール位置を追跡する必要があることです(おそらく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-

もう一度質問する必要があります。 @piecyk上からのコードサンプルを使用しています( @simjesに返信し
<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にフェッチしません

@ChristopherHButlerは、問題のコードサンドボックスの例がないと言うのが本当に難しいですが、何かを共有できますか?
ここでの基本的な考え方は、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を使用してスクロールが変更されるたびに更新されるため、小道具をスクロールバーに渡す必要はありません。

@piecykそれは素晴らしいです、ありがとう!
ところで、必要なのはonScroll関数(私が見逃した)だけのようで、参照を転送する必要はまったくありません。
https://codesandbox.io/s/bvaughnreact-window-react-scrollbars-custom-99dn1

@piecyk申し訳ありませんが、VariableSizeListの実装はAutoSizerにラップされており、それをレンダリングするコンポーネントはクラスベースのコンポーネントであるため、コンテキストを使用できるかどうか

クイックアップデート:
コンポーネントの状態を追加してonScrollに設定しました。

`
クラスBaseTreeはComponent {を拡張します
..。
state = {scrollPosition:0、};
..。
listRef = React.createRef();
outsideRef = React.createRef();
..。
レンダリング{
const {nodes、nodesFetching、nodesFetchingFailed、expandedNodes、selectedNode} = this.props;
戻る(

{({高さ、幅})=>(
ref = {this.listRef}
className = "リスト"
outsideRef = {this.outerRef}
outsideElementType = {TreeScrollbar}
width = {width}
height = {height}
onScroll = {({scrollOffset})=> this.setState({scrollPosition:scrollOffset})}
itemSize = {index => rowHeights [index]}
itemCount = {nodeTree.length}
itemData = {{
nodeTree、
ExpandedNodes、
ノードフェッチ、
nodesFetchingFailed、
selectedNode、
selectedNodeId、
resetRowHeight:this.resetRowHeight、
}}
>>
{ノード}

)}

);
}}

const mapStateToProps = state =>({
scrollPosition:selectors.getTreeScrollPosition(state)、
});

const mapDispatchToProps = dispatch =>({
setTreeScrollPosition:position => dispatch(actions.setTreeScrollPosition({position}))、
});

デフォルトの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 to react-windowは、 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がリストのレンダリングを遅らせて、this.listRef.currentを未定義にします。

ハッキーなオプションは、setTimeoutでライフサイクルを反応させ、次のティックでrefを呼び出すことです

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

@piecyk助けてくれてありがとう、本当に感謝しています:)

ありがとう@piecykそれは
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 評価