私が使用しています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; } }
を追加しました。
このライブラリとreact-virtualized
は完全に異なる実装です。 react-virtualized
問題で見られる一般的な手法は、何かにアプローチする方法について役立つヒントを提供することがよくありますが、このような特定の実装の詳細は適用されません。 ( react-virtualized
では、 List
は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}
/>
outerElementType
またはinnerElementType
を使用していくつの高度なことが可能であるかが大好きです
react-windowの下部にあるスクロール位置を検出しようとしています。
出来ますか? そのためのアイデアはありますか? codesandboxの例が
利用可能なrefpropsを使用して、リストにscrollHeight
@ rufootを要求できるはずです。
小道具でscrollHeight
を使おうとしました。 しかし、その中にはscrollHeight
プロパティはないと思います。
@bvaughnそれについて何か考えがありますか?
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のようなことができます
プロファイリングを行いませんでした。これがお役に立てば幸いです👍
@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
いますが、リストでも同じように機能するはずです。
それが役に立てば幸い。
最も参考になるコメント
より良いアプローチは、
Scrollbars
をouterElementType
として渡すことです。例https://codesandbox.io/s/vmr1l0p463