Skip to content

Commit 6de4b41

Browse files
Tom Hutmanjaapbakker88
andauthored
CRS-292 Prevent state updates on unmounted Channel component (#566)
* Add ref to keep track of whether component is mounted. Do not trigger state update if component has already been unmounted. * Separate logic into hook and add test Co-authored-by: jaapbakker88 <[email protected]>
1 parent 0fa172a commit 6de4b41

File tree

3 files changed

+28
-0
lines changed

3 files changed

+28
-0
lines changed

src/components/Channel/Channel.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import {
2323
} from '../Loading';
2424
import useMentionsHandlers from './hooks/useMentionsHandlers';
2525
import useEditMessageHandler from './hooks/useEditMessageHandler';
26+
import useIsMounted from './hooks/useIsMounted';
2627
import { channelReducer, initialState } from './channelState';
2728

2829
/** @type {React.FC<import('types').ChannelProps>}>} */
@@ -138,6 +139,7 @@ const ChannelInner = ({
138139
const lastRead = useRef(new Date());
139140
const chatContext = useContext(ChatContext);
140141
const online = useRef(true);
142+
const isMounted = useIsMounted();
141143
const { t } = useContext(TranslationContext);
142144

143145
// eslint-disable-next-line react-hooks/exhaustive-deps
@@ -270,6 +272,7 @@ const ChannelInner = ({
270272
* @param {import('stream-chat').ChannelState['messages']} messages
271273
*/
272274
(hasMore, messages) => {
275+
if (!isMounted.current) return;
273276
dispatch({ type: 'loadMoreFinished', hasMore, messages });
274277
},
275278
2000,
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { renderHook, act } from '@testing-library/react-hooks';
2+
import useIsMounted from '../hooks/useIsMounted';
3+
4+
describe('useIsMounted hook', () => {
5+
it('should set the value to false after unmounting', () => {
6+
const renderResult = renderHook(() => useIsMounted());
7+
const ref = renderResult.result.current;
8+
expect(ref.current).toBe(true);
9+
act(() => {
10+
renderResult.unmount();
11+
});
12+
expect(ref.current).toBe(false);
13+
});
14+
});
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { useRef, useEffect } from 'react';
2+
3+
export default () => {
4+
const isMounted = useRef(true);
5+
useEffect(() => {
6+
return () => {
7+
isMounted.current = false;
8+
};
9+
}, []);
10+
return isMounted;
11+
};

0 commit comments

Comments
 (0)