11import { hooks } from 'botframework-webchat-api' ;
2- import React , { Fragment , memo , MutableRefObject , useCallback , useMemo } from 'react' ;
2+ import React , { Fragment , memo , MutableRefObject , useCallback , useEffect , useMemo } from 'react' ;
33import { useAnimatingToEnd , useAtEnd , useScrollToEnd , useSticky } from 'react-scroll-to-bottom' ;
44import { useRefFrom } from 'use-ref-from' ;
55
@@ -8,6 +8,8 @@ import useFocusByActivityKey from '../../providers/TranscriptFocus/useFocusByAct
88
99const { useActivityKeysByRead, useCreateScrollToEndButtonRenderer, useMarkActivityKeyAsRead, useStyleOptions } = hooks ;
1010
11+ const EMPTY_ARRAY = Object . freeze ( [ ] ) ;
12+
1113const useScrollToEndRenderResult = ( terminatorRef : MutableRefObject < HTMLDivElement > ) => {
1214 const [ renderingActivityKeys ] = useRenderingActivityKeys ( ) ;
1315 const [ sticky ] : [ boolean ] = useSticky ( ) ;
@@ -46,18 +48,22 @@ const useScrollToEndRenderResult = (terminatorRef: MutableRefObject<HTMLDivEleme
4648
4749 // To prevent flashy button, we are not waiting for another render loop to update the `[readActivityKeys, unreadActivityKeys]` state.
4850 // Instead, we are building the next one in this `useMemo` call.
49- const nextUnreadActivityKeys = useMemo ( ( ) => {
50- // This code need to be careful reviewed as it will cause another render. The code should be converging.
51- // After we call `markActivityKeyAsRead`, everything will be read and nothing will be unread.
52- // That means, in next render, ` unreadActivityKeys` will be emptied and the `markActivityKeyAsRead` will not get called again.
53- if ( sticky && unreadActivityKeys . length ) {
54- markActivityKeyAsRead ( unreadActivityKeys [ unreadActivityKeys . length - 1 ] ) ;
55-
56- return [ ] ;
57- }
51+ const [ nextUnreadActivityKeys , activityKeyToMarkAsUnread ] = useMemo < readonly [ readonly string [ ] , string | undefined ] > (
52+ ( ) =>
53+ Object . freeze (
54+ sticky && unreadActivityKeys . length
55+ ? [ EMPTY_ARRAY , unreadActivityKeys [ unreadActivityKeys . length - 1 ] ]
56+ : [ unreadActivityKeys , undefined ]
57+ ) ,
58+ [ sticky , unreadActivityKeys ]
59+ ) ;
5860
59- return unreadActivityKeys ;
60- } , [ markActivityKeyAsRead , sticky , unreadActivityKeys ] ) ;
61+ // This code need to be careful reviewed as it will cause another render. The code should be converging.
62+ // After we call `markActivityKeyAsRead`, everything will be read and nothing will be unread.
63+ // That means, in next render, `unreadActivityKeys` will be emptied and the `markActivityKeyAsRead` will not get called again.
64+ useEffect ( ( ) => {
65+ activityKeyToMarkAsUnread && markActivityKeyAsRead ( activityKeyToMarkAsUnread ) ;
66+ } , [ activityKeyToMarkAsUnread , markActivityKeyAsRead ] ) ;
6167
6268 const nextUnreadActivityKeysRef = useRefFrom ( nextUnreadActivityKeys ) ;
6369
@@ -99,6 +105,7 @@ const useScrollToEndRenderResult = (terminatorRef: MutableRefObject<HTMLDivEleme
99105
100106function ScrollToEndButton ( { terminatorRef } : Readonly < { terminatorRef : MutableRefObject < HTMLDivElement > } > ) {
101107 const children = useScrollToEndRenderResult ( terminatorRef ) ;
108+
102109 return < Fragment > { children } </ Fragment > ;
103110}
104111
0 commit comments