Skip to content

Commit a2a9645

Browse files
authored
fix: prevent flashing EmptyStateIndicator in ChannelList before the first channels page is loaded (#2150)
1 parent f55c86f commit a2a9645

File tree

3 files changed

+50
-6
lines changed

3 files changed

+50
-6
lines changed

src/components/ChannelList/ChannelList.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,10 @@ const UnMemoizedChannelList = <
350350
<List
351351
error={channelsQueryState.error}
352352
loadedChannels={sendChannelsToList ? loadedChannels : undefined}
353-
loading={channelsQueryState.queryInProgress === 'reload'}
353+
loading={
354+
!!channelsQueryState.queryInProgress &&
355+
['reload', 'uninitialized'].includes(channelsQueryState.queryInProgress)
356+
}
354357
LoadingErrorIndicator={LoadingErrorIndicator}
355358
LoadingIndicator={LoadingIndicator}
356359
setChannels={setChannels}

src/components/ChannelList/__tests__/ChannelList.test.js

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ import {
3636
ChannelPreviewMessenger,
3737
} from '../../ChannelPreview';
3838

39-
import { ChatContext } from '../../../context/ChatContext';
39+
import { ChatContext, useChatContext } from '../../../context/ChatContext';
40+
import { ChannelListMessenger } from '../ChannelListMessenger';
4041

4142
expect.extend(toHaveNoViolations);
4243

@@ -256,6 +257,42 @@ describe('ChannelList', () => {
256257
expect(results).toHaveNoViolations();
257258
});
258259

260+
it('should render loading indicator before the first channel list load and on reload', async () => {
261+
const channelsQueryStatesHistory = [];
262+
const channelListMessengerLoadingHistory = [];
263+
useMockedApis(chatClient, [queryChannelsApi([testChannel1])]);
264+
265+
const QueryStateInterceptor = ({ children }) => {
266+
const { channelsQueryState } = useChatContext();
267+
channelsQueryStatesHistory.push(channelsQueryState.queryInProgress);
268+
return children;
269+
};
270+
271+
const ChannelListMessengerPropsInterceptor = (props) => {
272+
channelListMessengerLoadingHistory.push(props.loading);
273+
return <ChannelListMessenger {...props} />;
274+
};
275+
276+
await act(() => {
277+
render(
278+
<Chat client={chatClient}>
279+
<QueryStateInterceptor>
280+
<ChannelList List={ChannelListMessengerPropsInterceptor} />
281+
</QueryStateInterceptor>
282+
</Chat>,
283+
);
284+
});
285+
286+
expect(channelsQueryStatesHistory).toHaveLength(3);
287+
expect(channelListMessengerLoadingHistory).toHaveLength(3);
288+
expect(channelsQueryStatesHistory[0]).toBe('uninitialized');
289+
expect(channelListMessengerLoadingHistory[0]).toBe(true);
290+
expect(channelsQueryStatesHistory[1]).toBe('reload');
291+
expect(channelListMessengerLoadingHistory[1]).toBe(true);
292+
expect(channelsQueryStatesHistory[2]).toBeNull();
293+
expect(channelListMessengerLoadingHistory[2]).toBe(false);
294+
});
295+
259296
it('ChannelPreview UI components should render `Avatar` when the custom prop is provided', async () => {
260297
useMockedApis(chatClient, [queryChannelsApi([testChannel1])]);
261298

src/components/Chat/hooks/useChannelsQueryState.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,22 @@
11
import { Dispatch, SetStateAction, useState } from 'react';
22
import type { APIErrorResponse, ErrorFromResponse } from 'stream-chat';
33

4-
type ChannelQueryType = 'reload' | 'load-more';
4+
type ChannelQueryState =
5+
| 'uninitialized' // the initial state before the first channels query is trigerred
6+
| 'reload' // the initial channels query (loading the first page) is in progress
7+
| 'load-more' // loading the next page of channels
8+
| null; // at least one channels page has been loaded and there is no query in progress at the moment
59

610
export interface ChannelsQueryState {
711
error: ErrorFromResponse<APIErrorResponse> | null;
8-
queryInProgress: ChannelQueryType | null;
12+
queryInProgress: ChannelQueryState | null;
913
setError: Dispatch<SetStateAction<ErrorFromResponse<APIErrorResponse> | null>>;
10-
setQueryInProgress: Dispatch<SetStateAction<ChannelQueryType | null>>;
14+
setQueryInProgress: Dispatch<SetStateAction<ChannelQueryState | null>>;
1115
}
1216

1317
export const useChannelsQueryState = (): ChannelsQueryState => {
1418
const [error, setError] = useState<ErrorFromResponse<APIErrorResponse> | null>(null);
15-
const [queryInProgress, setQueryInProgress] = useState<ChannelQueryType | null>(null);
19+
const [queryInProgress, setQueryInProgress] = useState<ChannelQueryState>('uninitialized');
1620

1721
return {
1822
error,

0 commit comments

Comments
 (0)