Skip to content

Commit d07861f

Browse files
authored
feat: enable exhaustive-deps, but ignore all current errors (#2244)
### 🎯 Goal Generally, `react-hooks/exhaustive-deps` eslint rule is very useful, but for historical reasons it's not always followed in our SDK. We can't fix every place this rule is violated, but at least we want to have exhaustive deps moving forward. This PR enable this eslint rule, but adds in-place ignores everywhere it's currently violated. That way we can make fixes incrementally, and benefit from improved linting moving forward. ### 🛠 Implementation details All changes were made automatically (and manually reviewed afterwards): 1. Enable `react-hooks/exhaustive-deps` 2. Export all linting errors to `lint.json`: ```sh npx eslint 'src/**/*.{js,ts,tsx,md}' -f json -o lint.json ``` 3. Use this script to add in-place ignores (adapted from https://stackoverflow.com/questions/60629026/is-there-a-way-to-programmatically-suppress-all-eslint-errors-on-a-line-by-line): ```js const json = require('./lint.json'); const fs = require('fs'); json.forEach(({ filePath, messages, source }) => { if (!source) { return; } const data = source.split('\n'); let offset = 1; const groupedMessages = messages.reduce((acc, next) => { const prevMessages = acc[next.line] ? acc[next.line] : []; const duplicateRuleForLine = prevMessages.find((message) => message.ruleId === next.ruleId); const applicableRule = next.ruleId === 'react-hooks/exhaustive-deps'; if (duplicateRuleForLine || !applicableRule) { return acc; } return { ...acc, [next.line]: [...prevMessages, next], }; }, {}); Object.entries(groupedMessages).forEach(([line, messages]) => { const ignore = `// eslint-disable-next-line ${messages.map(({ ruleId }) => ruleId).join(' ')}`; data.splice(line - offset, 0, ignore); offset--; }); const updated = data.join('\n'); fs.writeFile(filePath, updated, function (err) { if (err) return console.log(err); }); }); ```
1 parent 651d3e7 commit d07861f

File tree

63 files changed

+89
-2
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+89
-2
lines changed

.eslintrc.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@
7979
"max-classes-per-file": 0,
8080
"camelcase": 0,
8181
"react-hooks/rules-of-hooks": 1,
82-
"react-hooks/exhaustive-deps": 0,
82+
"react-hooks/exhaustive-deps": 1,
8383
"jest/prefer-inline-snapshots": 0,
8484
"jest/lowercase-name": 0,
8585
"jest/prefer-expect-assertions": 0,
@@ -166,7 +166,7 @@
166166
"@typescript-eslint/ban-ts-comment": 0,
167167
"@typescript-eslint/no-unused-vars": 1,
168168
"@typescript-eslint/no-var-requires": 0,
169-
"react-hooks/exhaustive-deps": 0,
169+
"react-hooks/exhaustive-deps": 1,
170170
"react-native/no-inline-styles": 0,
171171
"array-callback-return": 2,
172172
"arrow-body-style": 2,

src/components/Attachment/Attachment.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ export const Attachment = <
8484
) => {
8585
const { attachments } = props;
8686

87+
// eslint-disable-next-line react-hooks/exhaustive-deps
8788
const groupedAttachments = useMemo(() => renderGroupedAttachments(props), [attachments]);
8889

8990
return (

src/components/Attachment/AttachmentContainer.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,7 @@ export const MediaContainer = <
260260
);
261261
setAttachmentConfiguration(config);
262262
}
263+
// eslint-disable-next-line react-hooks/exhaustive-deps
263264
}, [videoElement, videoAttachmentSizeHandler, attachment]);
264265

265266
const content = (

src/components/Attachment/hooks/useAudioController.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ export const useAudioController = () => {
4343
audioRef.current.play();
4444

4545
return () => {
46+
// eslint-disable-next-line react-hooks/exhaustive-deps
4647
audioRef.current?.pause();
4748

4849
window.clearInterval(interval);

src/components/Channel/Channel.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,7 @@ const ChannelInner = <
567567
client.off('user.deleted', handleEvent);
568568
notificationTimeouts.forEach(clearTimeout);
569569
};
570+
// eslint-disable-next-line react-hooks/exhaustive-deps
570571
}, [
571572
channel.cid,
572573
channelQueryOptions,
@@ -987,6 +988,7 @@ const ChannelInner = <
987988
skipMessageDataMemoization,
988989
updateMessage,
989990
}),
991+
// eslint-disable-next-line react-hooks/exhaustive-deps
990992
[
991993
channel.cid,
992994
deleteMessage,
@@ -1046,6 +1048,7 @@ const ChannelInner = <
10461048
TypingIndicator: props.TypingIndicator,
10471049
VirtualMessage: props.VirtualMessage,
10481050
}),
1051+
// eslint-disable-next-line react-hooks/exhaustive-deps
10491052
[props.reactionOptions],
10501053
);
10511054

src/components/Channel/__tests__/Channel.test.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ const CallbackEffectWithChannelContexts = ({ callback }) => {
6161
const channelActionContext = useChannelActionContext();
6262
const componentContext = useComponentContext();
6363

64+
// eslint-disable-next-line react-hooks/exhaustive-deps
6465
const channelContext = {
6566
...channelStateContext,
6667
...channelActionContext,

src/components/Channel/hooks/useCreateChannelStateContext.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ export const useCreateChannelStateContext = <
136136
watcherCount,
137137
watchers,
138138
}),
139+
// eslint-disable-next-line react-hooks/exhaustive-deps
139140
[
140141
channelId,
141142
debounceURLEnrichmentMs,

src/components/Channel/hooks/useCreateTypingContext.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export const useCreateTypingContext = <
1616
() => ({
1717
typing,
1818
}),
19+
// eslint-disable-next-line react-hooks/exhaustive-deps
1920
[typingValue],
2021
);
2122

src/components/ChannelList/ChannelList.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,11 +258,13 @@ const UnMemoizedChannelList = <
258258
setSearchActive(true);
259259
}
260260
additionalChannelSearchProps?.onSearch?.(event);
261+
// eslint-disable-next-line react-hooks/exhaustive-deps
261262
}, []);
262263

263264
const onSearchExit = useCallback(() => {
264265
setSearchActive(false);
265266
additionalChannelSearchProps?.onSearchExit?.();
267+
// eslint-disable-next-line react-hooks/exhaustive-deps
266268
}, []);
267269

268270
const { channels, hasNextPage, loadNextPage, setChannels } = usePaginatedChannels(
@@ -317,6 +319,7 @@ const UnMemoizedChannelList = <
317319
client.off('channel.deleted', handleEvent);
318320
client.off('channel.hidden', handleEvent);
319321
};
322+
// eslint-disable-next-line react-hooks/exhaustive-deps
320323
}, [channel?.cid]);
321324

322325
const renderChannel = (item: Channel<StreamChatGenerics>) => {

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1700,6 +1700,7 @@ describe('ChannelList', () => {
17001700
const { channels, setChannels } = useChannelListContext();
17011701
useEffect(() => {
17021702
setChannelsFromOutside = setChannels;
1703+
// eslint-disable-next-line react-hooks/exhaustive-deps
17031704
}, []);
17041705
return <div>{channelsToIdString(channels)}</div>;
17051706
};

0 commit comments

Comments
 (0)