Skip to content

Commit

Permalink
Merge pull request #4 from vu-luong/infinite-scroller
Browse files Browse the repository at this point in the history
add infinite scroller
  • Loading branch information
vu-luong authored May 29, 2022
2 parents 55ef1d4 + e91bd6a commit f4197e2
Show file tree
Hide file tree
Showing 3 changed files with 160 additions and 27 deletions.
141 changes: 128 additions & 13 deletions example/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,135 @@ 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 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(() => {
setMessagesModel([
...messagesModel,
{
isMe: true,
message: `${message}`,
},
{
isMe: false,
message: `${message}`,
},
{
isMe: false,
message: `${message}`,
},
]);
}, 1500);
};

const channelsModel = [
Expand All @@ -39,17 +160,6 @@ function App() {
},
];

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

return (
<div className="d-flex flex-row w-100 h-100 card shadow">
<div className="chat-list">
Expand All @@ -70,8 +180,13 @@ function App() {
<div className="rounded-0 shadow">
<MessageListHeader data={{ title: 'Channel Name', avatarUrl: '' }} />
</div>
<div className="message-list p-3 overflow-auto flex-1">
<MessageList dataSource={messagesModel} />
<div className="message-list flex-1 mh-100 h-100 overflow-auto">
<MessageList
dataSource={messagesModel}
triggerScrollToBottom={triggerScrollToBottom}
channelId={activeChannelId}
next={next}
/>
</div>
<ChatInput onSubmit={onSend} className="mx-3 mb-3" />
</div>
Expand Down
9 changes: 5 additions & 4 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.7",
"version": "0.0.8",
"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 @@ -43,10 +43,11 @@
"react-dom": "^18.1.0"
},
"dependencies": {
"@fortawesome/fontawesome-free": "^6.1.1",
"bootstrap": "4.6.0",
"classnames": "^2.3.1",
"prop-types": "^15.8.1",
"react-uuid": "^1.0.2",
"bootstrap": "4.6.0",
"@fortawesome/fontawesome-free": "^6.1.1"
"react-infinite-scroll-component": "^6.1.0",
"react-uuid": "^1.0.2"
}
}
37 changes: 27 additions & 10 deletions src/MessageList/MessageList.jsx
Original file line number Diff line number Diff line change
@@ -1,46 +1,63 @@
import React, { useEffect, useRef } from 'react';
import React, { useRef, useState } from 'react';
import InfiniteScroll from 'react-infinite-scroll-component';
import PropTypes from 'prop-types';
import uuid from 'react-uuid';
import MessageBubble from '../MessageBubble/MessageBubble';
import '../style.css';

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

const messagesEnd = useRef(null);
const [prevTriggerScroll, setPrevTriggerScroll] = useState(null);

const scrollToBottom = () => {
messagesEnd.current?.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'start' });
};

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

return (
<div>
<div className="d-flex flex-column">
<div className="overflow-auto mh-100 p-3 d-flex flex-column-reverse" id="scrollableDiv">
<div ref={messagesEnd} />
<InfiniteScroll
dataLength={dataSource.length}
next={next}
style={{ display: 'flex', flexDirection: 'column-reverse' }}
inverse
hasMore
loader={<div className="loader" key={0}>Loading ...</div>}
scrollableTarget="scrollableDiv"
>
{
dataSource.map((item, i) => (
<MessageBubble
key={uuid()}
// eslint-disable-next-line react/no-array-index-key
key={i}
id={i}
data={item}
/>
))
}
</div>
<div ref={messagesEnd} />
</InfiniteScroll>
</div>
);
}

MessageList.propTypes = {
dataSource: PropTypes.arrayOf(MessageBubble.propTypes.data),
triggerScrollToBottom: PropTypes.bool,
next: PropTypes.func,
};

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

export default MessageList;

0 comments on commit f4197e2

Please sign in to comment.