Skip to content

Commit

Permalink
CRS-292 Prevent state updates on unmounted Channel component (#566)
Browse files Browse the repository at this point in the history
* 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 <jaap@getstream.io>
  • Loading branch information
Tom Hutman and jaapbakker88 authored Oct 14, 2020
1 parent 0fa172a commit 6de4b41
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 0 deletions.
3 changes: 3 additions & 0 deletions src/components/Channel/Channel.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
} from '../Loading';
import useMentionsHandlers from './hooks/useMentionsHandlers';
import useEditMessageHandler from './hooks/useEditMessageHandler';
import useIsMounted from './hooks/useIsMounted';
import { channelReducer, initialState } from './channelState';

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

// eslint-disable-next-line react-hooks/exhaustive-deps
Expand Down Expand Up @@ -270,6 +272,7 @@ const ChannelInner = ({
* @param {import('stream-chat').ChannelState['messages']} messages
*/
(hasMore, messages) => {
if (!isMounted.current) return;
dispatch({ type: 'loadMoreFinished', hasMore, messages });
},
2000,
Expand Down
14 changes: 14 additions & 0 deletions src/components/Channel/__tests__/useIsMounted.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { renderHook, act } from '@testing-library/react-hooks';
import useIsMounted from '../hooks/useIsMounted';

describe('useIsMounted hook', () => {
it('should set the value to false after unmounting', () => {
const renderResult = renderHook(() => useIsMounted());
const ref = renderResult.result.current;
expect(ref.current).toBe(true);
act(() => {
renderResult.unmount();
});
expect(ref.current).toBe(false);
});
});
11 changes: 11 additions & 0 deletions src/components/Channel/hooks/useIsMounted.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { useRef, useEffect } from 'react';

export default () => {
const isMounted = useRef(true);
useEffect(() => {
return () => {
isMounted.current = false;
};
}, []);
return isMounted;
};

0 comments on commit 6de4b41

Please sign in to comment.