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
4 Answers
Reset to default 5I 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.