最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - React PerfectScrollBar scroll at bottom of container for dynamically generated content - Stack Overflow

programmeradmin2浏览0评论

I am using react perfectscrollbar

I am trying to implement the chat feature where on clicked on user, the chat message is requested via ajax and placed in the DOM. Here, I want the container to be scrolled at bottom.

I have implemented below code in react but it seems to be not working. Ant idea? Note: I have filtered the code and only pasted the related section. I have used the suggested method for scrollTop but it's not working.

 class Complain extends Component {
    constructor(props) {
        super(props);
        
        this.chatContainerRef = React.createRef();

    }
    
        viewComplain(e, id, name) {
        axios.get('/plain/' + id, {

        })
            .then(res => {
                const chatmsg = res.data.data;
                // let data = { msgdata: chatmsg, name: name, plainid: id };
                this.setState({ chatmsg: chatmsg });
                this.setState({ plainname: name });
                this.setState({ activeChat: id });
                this.setState({ plainRegNo: chatmsg[0].regno });
                console.log(this.chatContainerRef);
                this.chatContainerRef.current.scrollTop = 200;  // -> this is not working
            })
            .catch(function (error) {

            });
    }

render(
return {
    
 <PerfectScrollbar option={{ suppressScrollX: false }} ref={this.chatContainerRef}>
       {
              this.state.chatmsg.map((post, i) => (
                  <div key={i} className={(post.msg_creater === "school") ? "row flex-nowrap message-row contact p-4" : "row flex-nowrap message-row user p-4"}>
                  <img className="avatar mr-4" src="../assets/images/avatars/profile.jpg" alt="" />
                  <div className="bubble">
                      <div className="message">{post.msg}</div>
                      <div className="time text-muted text-right mt-2">{post.created_at}</div>
                  </div>
              </div>
           ))
       }
      </PerfectScrollbar>
})

I am using react perfectscrollbar https://www.npmjs./package/react-perfect-scrollbar

I am trying to implement the chat feature where on clicked on user, the chat message is requested via ajax and placed in the DOM. Here, I want the container to be scrolled at bottom.

I have implemented below code in react but it seems to be not working. Ant idea? Note: I have filtered the code and only pasted the related section. I have used the suggested method for scrollTop but it's not working.

 class Complain extends Component {
    constructor(props) {
        super(props);
        
        this.chatContainerRef = React.createRef();

    }
    
        viewComplain(e, id, name) {
        axios.get('/plain/' + id, {

        })
            .then(res => {
                const chatmsg = res.data.data;
                // let data = { msgdata: chatmsg, name: name, plainid: id };
                this.setState({ chatmsg: chatmsg });
                this.setState({ plainname: name });
                this.setState({ activeChat: id });
                this.setState({ plainRegNo: chatmsg[0].regno });
                console.log(this.chatContainerRef);
                this.chatContainerRef.current.scrollTop = 200;  // -> this is not working
            })
            .catch(function (error) {

            });
    }

render(
return {
    
 <PerfectScrollbar option={{ suppressScrollX: false }} ref={this.chatContainerRef}>
       {
              this.state.chatmsg.map((post, i) => (
                  <div key={i} className={(post.msg_creater === "school") ? "row flex-nowrap message-row contact p-4" : "row flex-nowrap message-row user p-4"}>
                  <img className="avatar mr-4" src="../assets/images/avatars/profile.jpg" alt="" />
                  <div className="bubble">
                      <div className="message">{post.msg}</div>
                      <div className="time text-muted text-right mt-2">{post.created_at}</div>
                  </div>
              </div>
           ))
       }
      </PerfectScrollbar>
})

Share Improve this question edited Jul 14, 2019 at 8:35 Kewin Dousse 4,0452 gold badges28 silver badges49 bronze badges asked Jul 14, 2019 at 6:08 user254153user254153 1,8835 gold badges44 silver badges87 bronze badges 3
  • 1) Why are you using setState different for every state value(side question) 2) ACan you provide with hosted example? – Mobeen Commented Jul 14, 2019 at 6:15
  • 1) Yes it can be used in single setState/ However by concern is on scrollTop right now for react-perfect-scrollbar in this question. Can you please help me. – user254153 Commented Jul 14, 2019 at 8:27
  • scrollTop can be relative. It's only after applied CSS (in any sort of hosted example) I may be able to help – Mobeen Commented Jul 14, 2019 at 9:57
Add a ment  | 

4 Answers 4

Reset to default 5

I hope this sample helps:

import React, { useEffect, useState } from 'react';
import PerfectScrollbar from 'react-perfect-scrollbar';


const Messages = () => {
    const [scrollEl, setScrollEl] = useState();

    useEffect(() => {
      if (scrollEl) {
        scrollEl.scrollTop = 100;
      }
    }, [scrollEl]);

    return (
            <PerfectScrollbar
              containerRef={ref => {
                setScrollEl(ref);
              }}
              >
            {/* ............. */}
              </PerfectScrollbar>
  );
};

export default Messages;

Another simple option is to add a span to the bottom of your content and then scroll that into view.

Note: I wasn't able to get the containerRef prop on Scrollbar to work properly so this was the next best option.

import React, { useLayoutEffect, useRef } from 'react';
import Scrollbar from 'react-perfect-scrollbar';

...

const MyComp: FunctionComponent = () => {
  const scrollRef = useRef<HTMLSpanElement>();
  
  useLayoutEffect(() => {
    if (scrollRef?.current) {
      scrollRef.current.scrollIntoView();
    }
  });
  
  return (
    <Scrollbar>
      {_.map(data, (d) => renderItem(d))}
      <span ref={scrollRef} />
    </Scrollbar>
  ) 
 }

Another option is to wrap the in custom ponent and set a prop for it's behaviour (up or down depending of scrolDown prop) and set to bottom depending of dynamically added content (children). For messaging app for example.

import { PositionProps } from '...styled';
import PerfectScrollbar from 'react-perfect-scrollbar';
import 'react-perfect-scrollbar/dist/css/styles.css';
import React, { useEffect, useRef } from 'react';

type TProps = PositionProps & {
  children: React.ReactNode;
  scrollDown?: boolean;
};

const ScrollBar = ({ scrollDown, children, ...rest }: TProps) => {
  const [scroller, setScroller] = React.useState<HTMLElement | null>(null);
  const prevChildrenHeight = useRef<number>(0);

  useEffect(() => {
    if (scroller) {
      const currentChildrenHeight = scroller.scrollHeight;
      if (prevChildrenHeight.current !== currentChildrenHeight) {
        prevChildrenHeight.current = currentChildrenHeight;
        if (scrollDown) {
          scroller.scrollTop = currentChildrenHeight;
        }
      }
    }
  }, [scrollDown, scroller, children]);

  return (
    <PerfectScrollbar containerRef={setScrollEl}>{children}</PerfectScrollbar>
  );
};

export default ScrollBar;

RPS exposes a method updateScroll on its ref (not to be confused with the "containerRef"!!).

You need to call that after your content has changed.

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论