Skip to content

Commit

Permalink
Merge pull request #5 from vu-luong/infinite-scroller
Browse files Browse the repository at this point in the history
fix infinite scrolling behavior, update example
  • Loading branch information
vu-luong authored May 31, 2022
2 parents f4197e2 + e180ac1 commit b727c4c
Show file tree
Hide file tree
Showing 4 changed files with 141 additions and 133 deletions.
131 changes: 16 additions & 115 deletions example/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import ChatList from '../src/ChatList/ChatList';
import ChatInput from '../src/ChatInput/ChatInput';
import MessageList from '../src/MessageList/MessageList';
import MessageListHeader from '../src/MessageListHeader/MessageListHeader';
import { messagesToAppend, initialMessages, MAX_NUM_MESSAGES } from './constants';
import 'bootstrap/dist/css/bootstrap.min.css';
import '@fortawesome/fontawesome-free/js/fontawesome';
import '@fortawesome/fontawesome-free/js/solid';
Expand All @@ -15,134 +16,33 @@ import './App.css';
function App() {
const [activeChannelId, setActiveChannelId] = useState(0);
const [triggerScrollToBottom, setTriggerScrollToBottom] = useState(false);
const [messagesModel, setMessagesModel] = useState([
{
isMe: true,
message: 'This is a message',
},
{
isMe: false,
message: 'This is a reply',
},
{
isMe: false,
message: 'This is a reply',
},
{
isMe: false,
message: 'This is a reply',
},
{
isMe: false,
message: 'This is a reply',
},
{
isMe: false,
message: 'This is a reply',
},
{
isMe: false,
message: 'This is a reply',
},
{
isMe: false,
message: 'This is a reply',
},
{
isMe: false,
message: 'This is a reply',
},
{
isMe: false,
message: 'This is a reply',
},
{
isMe: false,
message: 'This is a reply',
},
{
isMe: false,
message: 'This is a reply',
},
{
isMe: false,
message: 'This is a reply',
},
{
isMe: false,
message: 'This is a reply',
},
{
isMe: false,
message: 'This is a reply',
},
{
isMe: false,
message: 'This is a reply',
},
{
isMe: false,
message: 'This is a reply',
},
{
isMe: false,
message: 'This is a reply',
},
{
isMe: false,
message: 'This is a reply',
},
{
isMe: false,
message: 'End',
},

]);
const [messagesModel, setMessagesModel] = useState(initialMessages);

const onItemClick = (id) => {
setActiveChannelId(id);
setTriggerScrollToBottom(!triggerScrollToBottom);
};

const onSend = (message) => {
// eslint-disable-next-line no-console
console.log(`onSend(${message})`);
setMessagesModel([
{
isMe: true,
message: `${message}`,
},
{
isMe: false,
message: `${message}`,
},
{
isMe: false,
message: `${message}`,
},
...messagesModel,
]);
};

const next = () => {
const message = 'new message';
setTimeout(() => {
if (messagesModel.length <= 30) {
setMessagesModel([
...messagesModel,
{
isMe: true,
message: `${message}`,
},
{
isMe: false,
message: `${message}`,
},
{
isMe: false,
message: `${message}`,
message,
},
]);
}, 1500);
}
setTriggerScrollToBottom(!triggerScrollToBottom);
};

const next = () => {
if (messagesModel.length <= MAX_NUM_MESSAGES) {
setMessagesModel([
...messagesToAppend,
...messagesModel,
]);
}
};

const channelsModel = [
Expand Down Expand Up @@ -186,6 +86,7 @@ function App() {
triggerScrollToBottom={triggerScrollToBottom}
channelId={activeChannelId}
next={next}
hasMore={messagesModel.length <= MAX_NUM_MESSAGES}
/>
</div>
<ChatInput onSubmit={onSend} className="mx-3 mb-3" />
Expand Down
101 changes: 101 additions & 0 deletions example/constants.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
const MAX_NUM_MESSAGES = 50;

const initialMessages = [
{
isMe: true,
message: 'This is a message',
},
{
isMe: false,
message: 'This is a reply',
},
{
isMe: false,
message: 'This is a reply',
},
{
isMe: false,
message: 'This is a reply',
},
{
isMe: false,
message: 'This is a reply',
},
{
isMe: false,
message: 'This is a reply',
},
{
isMe: false,
message: 'This is a reply',
},
{
isMe: false,
message: 'This is a reply',
},
{
isMe: false,
message: 'This is a reply',
},
{
isMe: false,
message: 'This is a reply',
},
{
isMe: false,
message: 'This is a reply',
},
{
isMe: false,
message: 'This is a reply',
},
{
isMe: false,
message: 'This is a reply',
},
{
isMe: false,
message: 'This is a reply',
},
{
isMe: false,
message: 'This is a reply',
},
{
isMe: false,
message: 'This is a reply',
},
{
isMe: false,
message: 'This is a reply',
},
{
isMe: false,
message: 'This is a reply',
},
{
isMe: false,
message: 'End',
},
];

const messagesToAppend = [
{
isMe: true,
message: 'Message',
},
{
isMe: false,
message: 'Message',
},
{
isMe: false,
message: 'Message',
},
];

export {
initialMessages,
messagesToAppend,
MAX_NUM_MESSAGES,
};
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-bootstrap-chat-ui",
"version": "0.0.8",
"version": "0.0.9",
"description": "UIkit for chat application using react and bootstrap",
"main": "dist/bundle/cjs/react-bootstrap-chat-ui.min.js",
"module": "dist/esm/index.js",
Expand Down Expand Up @@ -47,7 +47,7 @@
"bootstrap": "4.6.0",
"classnames": "^2.3.1",
"prop-types": "^15.8.1",
"react-infinite-scroll-component": "^6.1.0",
"react-infinite-scroller": "^1.2.6",
"react-uuid": "^1.0.2"
}
}
38 changes: 22 additions & 16 deletions src/MessageList/MessageList.jsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import React, { useRef, useState } from 'react';
import InfiniteScroll from 'react-infinite-scroll-component';
import React, { useEffect, useRef, useState } from 'react';
import InfiniteScroll from 'react-infinite-scroller';
import PropTypes from 'prop-types';
import MessageBubble from '../MessageBubble/MessageBubble';
import '../style.css';

function MessageList(props) {
const {
dataSource, triggerScrollToBottom, next,
dataSource, triggerScrollToBottom, next, hasMore,
} = props;

const messagesEnd = useRef(null);
Expand All @@ -16,34 +16,38 @@ function MessageList(props) {
messagesEnd.current?.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'start' });
};

if (triggerScrollToBottom !== prevTriggerScroll) {
scrollToBottom();
setPrevTriggerScroll(triggerScrollToBottom);
}
useEffect(() => {
if (triggerScrollToBottom !== prevTriggerScroll) {
scrollToBottom();
setPrevTriggerScroll(triggerScrollToBottom);
}
}, [triggerScrollToBottom]);

return (
<div className="overflow-auto mh-100 p-3 d-flex flex-column-reverse" id="scrollableDiv">
<div ref={messagesEnd} />
<div className="overflow-auto mh-100 p-3 d-flex flex-column overflow-auto" id="scrollableDiv">
<InfiniteScroll
dataLength={dataSource.length}
next={next}
style={{ display: 'flex', flexDirection: 'column-reverse' }}
inverse
hasMore
pageStart={0}
loadMore={next}
hasMore={hasMore}
style={{ display: 'flex', flexDirection: 'column' }}
loader={<div className="loader" key={0}>Loading ...</div>}
scrollableTarget="scrollableDiv"
useWindow={false}
threshold={25}
initialLoad={false}
isReverse
>
{
dataSource.map((item, i) => (
<MessageBubble
// eslint-disable-next-line react/no-array-index-key
key={i}
key={i + 1}
id={i}
data={item}
/>
))
}
</InfiniteScroll>
<div ref={messagesEnd} />
</div>
);
}
Expand All @@ -52,12 +56,14 @@ MessageList.propTypes = {
dataSource: PropTypes.arrayOf(MessageBubble.propTypes.data),
triggerScrollToBottom: PropTypes.bool,
next: PropTypes.func,
hasMore: PropTypes.bool,
};

MessageList.defaultProps = {
dataSource: [],
triggerScrollToBottom: false,
next: null,
hasMore: false,
};

export default MessageList;

0 comments on commit b727c4c

Please sign in to comment.