React-window: رد فعل شريط التمرير المخصص مع نافذة رد الفعل

تم إنشاؤها على ١٧ ديسمبر ٢٠١٨  ·  35تعليقات  ·  مصدر: bvaughn/react-window

أنا أستخدم react-custom-scrollbar وأود دمجه مع FixedSizeList .

لقد راجعت الحل الخاص بهذه المشكلة على react-virtualized : https://github.com/bvaughn/react-virtualized/issues/692#issuecomment -339393521

لكن الكود يقوم بإلقاء الخطأ: Uncaught TypeError: Cannot read property 'handleScrollEvent' of undefined عند التمرير ، في هذه الوظيفة:

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

    const { Grid: grid } = this.List;

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

لقد أضفت ref={ instance => { this.List = instance; } } على المكوِّن Fixixe <List .

💬 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-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}
/>

مثال https://codesandbox.io/s/vmr1l0p463

أحب عدد الأشياء المتقدمة الممكنة باستخدام outerElementType أو innerElementType

أحاول اكتشاف موضع التمرير أسفل نافذة التفاعل.
هل هو ممكن؟ هل لديك أي أفكار لذلك؟ أرغب في الحصول على مثال على الشفرات والصناديق .

يجب أن تكون قادرًا على استخدام دعائم المرجع المتاحة لطلب القائمة 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 لم يقاتلها ، هل يمكنك مشاركة Code Sandbox عندما يصبح بطيئًا؟

rufoot شيء مثل هذا https://codesandbox.io/s/4zjwwq98j4 ؟

أنا أستخدم التنفيذ الخاص بك ولكني أحصل على خطأ يقول أن إعادة التوجيه ريف ليست وظيفة.

المشكلة في تطبيقي التي أحاول حلها هي أن لدي قائمة كبيرة من العناصر وعندما أنقر على أحدها ، سيعيد التطبيق التوجيه إلى مسار آخر لذلك أحتاج إلى تتبع موضع التمرير (ربما يكون في حالة إعادة) و ثم اضبط موضع التمرير بعد تغيير المسار.

هل حاولت دمجها مع InfiniteLoader من react-window-infinite-loader .
أنا أستخدم 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>

تحديث: لا أعتقد أنه مرتبط بمكون التمرير اللانهائي. لا يمكنني الحصول عليه للعمل مع شريط التمرير المخصص.

سأكون ممتنًا إذا كان بمقدور شخص ما مشاركة تنفيذ رد فعل التمرير المخصص معي

ranihorev هل تحتاج إلى استخدام هذه الحزمة؟ يستخدم رمز القلم piecyk الذي تمت مشاركته أعلاه أشرطة تمرير مخصصة للتفاعل ويعمل بشكل جيد (باستثناء عند إنشاء مرجع ، والذي لسبب ما يكون فارغًا في الكود الخاص بي)

حسنًا ، أريد أن أسأل مرة أخرى. piecyk أنا أستخدم نموذج الشفرة الخاص بك من الأعلى (حيث أجبت على simjes ). بدلاً من استخدام قائمة ذات حجم ثابت على الرغم من ذلك ، فأنا أستخدم أداة الحجم التلقائي لالتفاف قائمة VariableSizeList وتحديد النوع الخارجي. شيء من هذا القبيل:
<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 كما هو الحال لديك ولكن المرجع دائمًا ما يكون فارغًا. لقد حاولت إنشاء المرجع في المكون الذي أستخدمه في AutoSizer وكذلك في الأصل ولكنه دائمًا فارغ. سأكون ممتنًا حقًا لبعض المساعدة في فهم السبب. كما ذكرت أعلاه ، أحتاج إلى تتبع موضع التمرير وأن أكون قادرًا على ضبطه على تغيير المسار في تطبيقي حتى لا تقفز القائمة مرة أخرى إلى الأعلى.

ChristopherHButler أنا أستخدم بالفعل هذه الحزمة عدة مرات في الكود الخاص بي ، لذلك أفضل الاستمرار في استخدام نفس الحزمة. أنا حل مشابه جدًا ولكنه لا يجلب بيانات جديدة بشكل صحيح

من الصعب حقًا
الفكرة الأساسية هنا هي تعيين المرجع من أشرطة التمرير الخاصة بالتفاعل بحيث تكون نافذة التفاعل

سيعمل AutoSizer أو VariableSizeList مع هذا النهج ، كما في هذا المثال
https://codesandbox.io/s/react-window-custom-scrollbars-t4352

ranihorev هل يمكنك أيضًا مشاركة مثال Code Sandbox؟

piecyk أنشأت مثالًا بسيطًا (
https://codesandbox.io/s/bvaughnreact-window-fixed-size-list-vertical-64kzh؟fontsize=14

لقد جربت أيضًا أشكالًا أخرى (على سبيل المثال ، تعيين المرجع ليكون غلاف سكرولر) ولكن لم ينجح ...

شكرا!

ranihorev سيكون هذا الأسلوب هو نفسه بغض النظر عن تنفيذ التمرير المخصص. يحتاجون إلى تعيين مرجع إلى نفس العنصر المسؤول عن التمرير والتعامل مع حدث التمرير هذا.

react-scrollbars-custom واجهة برمجة تطبيقات أجمل باستخدام نمط الدعائم حتى تتمكن من القيام بشيء مثل https://codesandbox.io/s/bvaughnreact-window-react-scrollbars-custom-pjyxs

لم أفعل أي تنميط ، آمل أن يساعد هذا 👍

piecyk أعمل مع العرض التوضيحي الخاص بك هنا: https://codesandbox.io/s/4zjwwq98j4 . أريد استخدام onScrollStop لإرسال إجراء في redux حتى أتمكن من تعيين موضع التمرير (فكرة من هذا الموضوع: https://github.com/malte-wessel/react-custom-scrollbars/issues/146 ولكن onScrollStart and لا يبدو أن onScrollStop يعمل في الكود الخاص بي أو في العرض التوضيحي الخاص بك. هل تعرف سبب ذلك؟ هل هناك أي طريقة لتمرير الدعائم من القائمة إلى أشرطة التمرير؟

ChristopherHButler أعتقد أن أفضل خيار لك هو استخدام السياق لتمرير الدعائم ، شيء مثل

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

- تم التحرير
إذا قمت بإلغاء تحميل القائمة بأكملها عند تغيير المسار ، فيمكنك إرسال الإجراء ، ثم ، يمكن تخزين Last scrollOffset في المرجع وتحديثه عند كل تغيير في التمرير باستخدام onScroll: function من VariableSizeList ، فلن تحتاج إلى تمرير الدعائم إلى Scrollbars

pieceyk هذا رائع ، شكرا!
راجع للشغل ، يبدو أن كل ما تحتاجه هو وظيفة onScroll (التي فاتني) وليس هناك حاجة لإعادة توجيه المرجع على الإطلاق.
https://codesandbox.io/s/bvaughnreact-window-react-scrollbars-custom-99dn1

piecyk آسف ، كان يجب أن

تحديث سريع:
أضفت حالة المكون وقمت بتعيينها على التمرير.

"
تمدد فئة BaseTree المكون {
...
state = {scrollPosition: 0،} ؛
...
listRef = React.createRef () ،
OuterRef = React.createRef () ،
...
يقدم - يجعل {
const {nodes، nodesFetching، nodesFetchingFailed، expandNodes، selectedNode} = this.props؛
إرجاع (

{({height، width}) => (
المرجع = {this.listRef}
className = "قائمة"
OuterRef = {this.outerRef}
ExternalElementType = {TreeScrollbar}
العرض = {العرض}
الارتفاع = {الارتفاع}
onScroll = {({scrollOffset}) => this.setState ({scrollPosition: scrollOffset})}
itemSize = {index => rowHeights [index]}
itemCount = {nodeTree.length}
itemData = {{
nodeTree
العقد الموسعة
العقد
العقد فشل الجلب ،
العقدة المحددة ،
العقدة المحددة ،
resetRowHeight: this.resetRowHeight ،
}}
>
{العقدة}

)}

) ؛
}}

const mapStateToProps = state => ({
scrollPosition: selectors.getTreeScrollPosition (حالة) ،
}) ؛

const mapDispatchToProps = إرسال => ({
setTreeScrollPosition: position => dispatch (Actions.setTreeScrollPosition ({position})) ،
}) ؛

تصدير الاتصال الافتراضي (mapStateToProps ، mapDispatchToProps) (BaseTree) ؛
"

ثم في componentWillUnmout ، أرسل الإجراء لتعيين الموضع في redux مثل هذا:

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

مشكلتي الوحيدة الآن هي القدرة على تعيين موضع التمرير عند إعادة تثبيت المكون. حاولت الوصول إلى طريقة scrollTop في هذه القائمة.

this.listRef.current.scrollTop() لكنني أتلقى خطأ مفاده أنها ليست وظيفة. لست متأكدًا من الخاصية (this.listRef أو this.outerRef) التي يمكنني استخدامها لتعيين موضع التمرير أو بأي طريقة. كنت أفكر في أنه يمكنني تعيينه في المكون المكون من BaseTree على النحو التالي:
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 في الحالة لأنك لست بحاجة إليها أثناء التمرير يحدث ، أقل من عمليات إعادة العرض ، قم بتخزينها في المرجع.

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 ، واستدعاء المرجع في العلامة التالية

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

شكرا جزيلا على بيسيك للمساعدة ، أنا حقا أقدر ذلك :)

شكرا piecyk يبدو أن هذا العمل. هناك وميض طفيف عند التركيب بعد تغيير المسار ولكن يمكنني التعايش معه :) لقد جربت أيضًا اختراقًا آخر وهو استخدام className لتمرير scrollPosition وتعيين scrollTop في refSetter لأشرطة CustomScrollbars:
if (scrollbarsRef) { forwardedRef(scrollbarsRef.view); // HACK scrollbarsRef.scrollTop(className); }
يبدو انه يشتغل جيدا.
شكرا مرة أخرى على كل ما قدمتموه من مساعدة ، إنه ممتن للغاية !! 🙌🏻

لسوء الحظ ، لا تعمل جميع الأمثلة في هذه المشكلة بشكل صحيح (أحيانًا يتوقف الماوس عن الاستجابة للتمرير).

لكن هذا المثال يعمل بشكل مثالي!

ranihorev سيكون هذا الأسلوب هو نفسه بغض النظر عن تنفيذ التمرير المخصص. يحتاجون إلى تعيين مرجع إلى نفس العنصر المسؤول عن التمرير والتعامل مع حدث التمرير هذا.

react-scrollbars-custom واجهة برمجة تطبيقات أجمل باستخدام نمط الدعائم حتى تتمكن من القيام بشيء مثل 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 التقييمات