react-infinite-scroller icon indicating copy to clipboard operation
react-infinite-scroller copied to clipboard

isReverse props

Open rahmatkruniawan opened this issue 6 years ago • 21 comments

i want use isReverse props but when I rendereing scroll always in top of element. So automatically load more items. How I to prevent autoload and put scroll in bottom when first load.

rahmatkruniawan avatar Jul 06 '17 05:07 rahmatkruniawan

I've actually never used the isReverse prop but I imagine it should be used like this:

componentDidMount() {
    if(this._chatbox) {
        this._chatbox.scrollTop = this._chatbox.scrollHeight;
    }
}
<div
    className="chatbox"
    ref={c => this._chatbox = c}
>
    <InfiniteScroll
        ...
        isReverse
    >
        {items}
    </InfiniteScroll>
</div>

danbovey avatar Jul 06 '17 10:07 danbovey

I changed to ` componentDidMount(){ this.scrollToBottom(); this.setState({ hasMore : false }) }

componentDidUpdate() {
  
  if (this.state.first) {
  	this.scrollToBottom();
 	this.setState({
			hasMore : true,
			first : false
		}) 	
  }
}
{items}
{ this.messagesEnd = el; }} />
	</div>`

But I got more porblem when I scrolling to the top. The scrollbar not bounced like usual when we use without reverse. So when scroll in top they load all data in same time not one by one . layout

rahmatkruniawan avatar Jul 06 '17 23:07 rahmatkruniawan

I was just struggling with this and handle it that way:

goToPrevScroll = (oldScrollHeight) => {
    const list = document.getElementById('messages-list');
    list.scrollTop = list.scrollHeight - oldScrollHeight + list.scrollTop;
}
handleStackMessages = (page) => {
    const list = document.getElementById('messages-list');
    let oldScrollHeight = this.list.scrollHeight;

    getDataFromApi.then(({ data }) => {
        saveYourDataInStateOrStore(data).then(() => {

            // scroll works different on firefox and chrome
            if(isFirefox) {
                // scroll to previous position on firefox
                this.goToPrevScroll(oldScrollHeight);
            } else if(list.scrollTop === 0) {
                // change scrolltop to prevent loading all pages at once on chrome
                this.goToPrevScroll(oldScrollHeight);            
            }
        });
    });
}

sorry for code style, I really don't understand this markdown editor.

EDIT - Fixed code style ^

tomasz89nowak avatar Oct 06 '17 07:10 tomasz89nowak

@tomasz89nowak , this code is awesome!! Thank you! One comment though, In my case I wanted to goToPrevScroll(oldScrollHeight) every time the loadMore fires, not only when the scrollTop === 0

Anyway, this helps alot!

@danbovey - I would consider adding something like this in Readme file, because this is the expected functionality every time you want to use isReverse prop

danielkrich avatar Nov 15 '17 10:11 danielkrich

That exact functionality is included in the component here https://github.com/CassetteRocks/react-infinite-scroller/blob/54d7b16a257687d6382c04300812f630cee54466/src/InfiniteScroll.js#L50-L57 it just doesn't work at the moment.

mxstbr avatar Mar 12 '19 13:03 mxstbr

The reason it does not work is because that runs synchronously, but loadMore (in most cases) runs asynchronously.

The only fix I can think of is requiring loadMore to return a Promise, and then running that code in loadMore.then(() => isReverse ? fixScrollPosition() : null).

mxstbr avatar Mar 12 '19 13:03 mxstbr

Hmmm... if isReverse is true, the initial scroll position should always start at the bottom (without any hacks needed). Will you accept a merge request or is this intended behaviour?

gtaylor44 avatar Apr 11 '19 14:04 gtaylor44

is the a demo solution for this, cause right now it keeps loading like mad, and scroll bar keeps on top. ( working with the demo files )

BenGreybox avatar Jun 19 '19 12:06 BenGreybox

for me, the functionality in the component works fine (also with an async loadMore function).

However, I had massive problems on iOS Safari due to the fact that when using -webkit-overflow-scrolling: touch it's not possible to set a scrollTop on an element while it still has some of the "bounce". Using this fix worked for me:

if (this.props.isReverse && this.loadMore) { 
   const parentElement = this.getParentElement(this.scrollComponent); 
   parentElement.style['-webkit-overflow-scrolling'] = 'auto';
   parentElement.scrollTop = 
     parentElement.scrollHeight - 
     this.beforeScrollHeight + 
     this.beforeScrollTop; 
   parentElement.style['-webkit-overflow-scrolling'] = 'touch';
   this.loadMore = false;
}

flache avatar Jun 27 '19 18:06 flache

em.. how to to solve this problem? I also have this pro, after loadMore the scrollbar is not correct

x1nGoo avatar Jun 28 '19 09:06 x1nGoo

me too.

ThaddeusJiang avatar Jul 22 '19 07:07 ThaddeusJiang

Is this library dead?

ghost avatar Apr 29 '20 09:04 ghost

How to solve this problem?

duarte-evocorp avatar Aug 03 '20 21:08 duarte-evocorp

My solution is:

const [hasMoreItems, setHasMoreItems] = useState(true);
const commentsRef = useRef();

const goToPrevScroll = (oldHeight = 0) => {
    const { current } = commentsRef;

    if (current) {
      current.scrollTop = current.scrollHeight - oldHeight + current.scrollTop;
    }
  };

const handleFetchMessages = async page => {
    const oldHeight = commentsRef.current && commentsRef.current.scrollHeight;

    const { data, headers } = await fetchMessages(page);

    const total = Number(headers['x-total-count']);
    const totalPages = Math.ceil(total / MIN_BATCH_SIZE);

    setHasMoreItems(page < totalPages);
    setMessages(data.reverse().concat(messages));

    if (commentsRef.current && commentsRef.current.scrollTop === 0) {
      goToPrevScroll(oldHeight);
    }
  };

...

<div className="scroll-wrap" ref={commentsRef}>
  <InfiniteScroll
          pageStart={0}
          initialLoad
          loadMore={handleFetchMessages}
          hasMore={hasMoreItems}
          loader={<Loading />}
          useWindow={false}
          isReverse
          threshold={150}
        >
          {messages.map(comment => (
            ...
          ))}
  </InfiniteScroll>
</div>

ghost avatar Aug 04 '20 07:08 ghost

@danbovey Why we need to use hacks for such a common use? I think i'm going to abandon this library because of this. that's a shame...

oran1248 avatar Aug 06 '20 20:08 oran1248

I also abandoned when I realised this functionality was missing.

I ended up using react-perfect-scrollbar with an adhoc solution.

https://www.npmjs.com/package/react-perfect-scrollbar

gtaylor44 avatar Aug 07 '20 01:08 gtaylor44

I'm able to get this mostly working in isReverse mode but I've spent the last two days running into issues due to scrolling to the top too fast. The scrollbar gets "stuck" at top and future elements being loaded don't offset the scroll position as they should. Very frustrating. Abandoning this package and using react-waypoints and apollo for reverse infinite scrolling.

kindmind avatar Sep 09 '20 01:09 kindmind

My solution is:

const [hasMoreItems, setHasMoreItems] = useState(true);
const commentsRef = useRef();

const goToPrevScroll = (oldHeight = 0) => {
    const { current } = commentsRef;

    if (current) {
      current.scrollTop = current.scrollHeight - oldHeight + current.scrollTop;
    }
  };

const handleFetchMessages = async page => {
    const oldHeight = commentsRef.current && commentsRef.current.scrollHeight;

    const { data, headers } = await fetchMessages(page);

    const total = Number(headers['x-total-count']);
    const totalPages = Math.ceil(total / MIN_BATCH_SIZE);

    setHasMoreItems(page < totalPages);
    setMessages(data.reverse().concat(messages));

    if (commentsRef.current && commentsRef.current.scrollTop === 0) {
      goToPrevScroll(oldHeight);
    }
  };

...

<div className="scroll-wrap" ref={commentsRef}>
  <InfiniteScroll
          pageStart={0}
          initialLoad
          loadMore={handleFetchMessages}
          hasMore={hasMoreItems}
          loader={<Loading />}
          useWindow={false}
          isReverse
          threshold={150}
        >
          {messages.map(comment => (
            ...
          ))}
  </InfiniteScroll>
</div>

angelitolm avatar Sep 26 '20 21:09 angelitolm

Hello I would like to know how I could implement this same code but already receiving the data by props instead of doing a fetch

angelitolm avatar Sep 26 '20 21:09 angelitolm

@gtaylor44, does this new library have a reverse scroll option?

duarte-evocorp avatar Sep 28 '20 11:09 duarte-evocorp

React-perfect-scrollbar has props you can hook into such as: onYReachStart onScrollUp onYReachEnd

But you will still have to deal with issues that @kindmind has mentioned such as "The scrollbar gets stuck" when the user drags scrollbar to the top with mouse. You can work around the "stuck scrollbar" by having an interval that checks if scrollTop = 0 and scrollBy 1 (for top) and -1 (for bottom).

Here are some screen captures for inspiration with react-perfect-scrollbar. App attempts to load more records before user actually hits the top of scrollbar by using combination of onScrollUp prop and scrollTop position.

screen-capture.zip

mouse-stuck-problem.zip

gtaylor44 avatar Sep 28 '20 12:09 gtaylor44