Update ChatPanel to handle scroll position and message fetching

- Added selectors for isTop, isBottom, and isMiddle in chatSlice.
- Removed scrollPosition and stopScrolling states from ChatPanel.
- Added onScrollPositionChange function to handle scroll events.
- Dispatch onMessagesTop, onMessagesBottom, and onMessagesMiddle actions based on scroll position.
This commit is contained in:
Rankin Zheng 2023-06-13 11:54:31 +08:00
parent ec440be005
commit 9a906a1c0f
2 changed files with 50 additions and 15 deletions

View File

@ -24,6 +24,12 @@ import {
selectErrorMessage,
selectMessages,
selectMessageCount,
selectIsBottom,
selectIsTop,
selectIsMiddle,
onMessagesBottom,
onMessagesTop,
onMessagesMiddle,
fetchHistoryMessages,
} from './chatSlice';
@ -89,22 +95,38 @@ const chatPanel = () => {
const errorMessage = useAppSelector(selectErrorMessage);
const messages = useAppSelector(selectMessages);
const messageCount = useAppSelector(selectMessageCount);
const isTop = useAppSelector(selectIsTop);
const isBottom = useAppSelector(selectIsBottom);
const isMiddle = useAppSelector(selectIsMiddle);
const [chatContainerRef, chatContainerRect] = useResizeObserver();
const scrollViewport = useRef<HTMLDivElement>(null);
const { height, width } = useViewportSize();
const [scrollPosition, onScrollPositionChange] = useState({ x: 0, y: 0 });
const [stopScrolling, setStopScrolling] = useState(false);
const scrollToBottom = () =>
scrollViewport?.current?.scrollTo({ top: scrollViewport.current.scrollHeight, behavior: 'smooth' });
const timer = useTimeout(() => {
// console.log(`stopScrolling:${stopScrolling}`);
if (!stopScrolling) {
if (isBottom) {
scrollToBottom();
}
}, 1000);
const onScrollPositionChange = ({ x, y }) => {
const sh = scrollViewport.current?.scrollHeight || 0;
const vh = scrollViewport.current?.clientHeight || 0;
const gap = sh - vh - y;
const isBottom = sh < vh ? true : gap < 100;
const isTop = y === 0;
// console.log(`sh:${sh},vh:${vh},x:${x},y:${y},gap:${gap}`);
if (isBottom) {
dispatch(onMessagesBottom());
} else if (isTop) {
dispatch(onMessagesTop());
} else {
dispatch(onMessagesMiddle());
}
};
useEffect(() => {
dispatch(fetchHistoryMessages());
messageUtil.registerHandler('receiveMessagePartial', (message: { text: string; }) => {
@ -122,17 +144,6 @@ const chatPanel = () => {
};
}, []);
useEffect(() => {
const sh = scrollViewport.current?.scrollHeight || 0;
const vh = scrollViewport.current?.clientHeight || 0;
const isBottom = sh < vh ? true : sh - vh - scrollPosition.y < 3;
if (isBottom) {
setStopScrolling(false);
} else {
setStopScrolling(true);
}
}, [scrollPosition]);
useEffect(() => {
if (generating) {
// new a bot message

View File

@ -24,6 +24,9 @@ export const chatSlice = createSlice({
errorMessage: '',
messages: <any>[],
messageCount: 10,
isBottom: true,
isMiddle: false,
isTop: false,
},
reducers: {
startGenerating: (state, action) => {
@ -71,6 +74,21 @@ export const chatSlice = createSlice({
},
happendError: (state, action) => {
state.errorMessage = action.payload;
},
onMessagesTop: (state) => {
state.isTop = true;
state.isBottom = false;
state.isMiddle = false;
},
onMessagesBottom: (state) => {
state.isTop = false;
state.isBottom = true;
state.isMiddle = false;
},
onMessagesMiddle: (state) => {
state.isTop = false;
state.isBottom = false;
state.isMiddle = true;
}
},
extraReducers: (builder) => {
@ -99,6 +117,9 @@ export const selectCurrentMessage = (state: RootState) => state.chat.currentMess
export const selectErrorMessage = (state: RootState) => state.chat.errorMessage;
export const selectMessages = (state: RootState) => state.chat.messages;
export const selectMessageCount = (state: RootState) => state.chat.messageCount;
export const selectIsBottom = (state: RootState) => state.chat.isBottom;
export const selectIsTop = (state: RootState) => state.chat.isTop;
export const selectIsMiddle = (state: RootState) => state.chat.isMiddle;
export const {
@ -112,6 +133,9 @@ export const {
popMessage,
clearMessages,
updateMessage,
onMessagesTop,
onMessagesBottom,
onMessagesMiddle,
} = chatSlice.actions;
export default chatSlice.reducer;