Tools: Add react-hooks/exhaustive-deps eslint rule

pull/6762/head^2
Laurent Cozic 2022-08-19 12:10:04 +01:00
parent 549095f0e5
commit 7e8a6dfb54
48 changed files with 127 additions and 14 deletions

View File

@ -83,7 +83,9 @@ module.exports = {
// 'complexity': ['warn', { max: 10 }],
// Checks rules of Hooks
'react-hooks/rules-of-hooks': 'error',
'@seiyab/react-hooks/rules-of-hooks': 'error',
'@seiyab/react-hooks/exhaustive-deps': ['error', { 'ignoreThisDependency': 'props' }],
// Checks effect dependencies
// Disable because of this: https://github.com/facebook/react/issues/16265
// "react-hooks/exhaustive-deps": "warn",
@ -134,7 +136,10 @@ module.exports = {
'plugins': [
'react',
'@typescript-eslint',
'react-hooks',
// Need to use a fork of the official rules of hooks because of this bug:
// https://github.com/facebook/react/issues/16265
'@seiyab/eslint-plugin-react-hooks',
// 'react-hooks',
'import',
],
'overrides': [

View File

@ -62,6 +62,7 @@
}
},
"devDependencies": {
"@seiyab/eslint-plugin-react-hooks": "^4.5.1-alpha.5",
"@typescript-eslint/eslint-plugin": "^4.6.0",
"@typescript-eslint/parser": "^4.6.0",
"cspell": "^5.20.0",
@ -69,7 +70,6 @@
"eslint-interactive": "^10.0.0",
"eslint-plugin-import": "^2.20.2",
"eslint-plugin-react": "^7.18.0",
"eslint-plugin-react-hooks": "^2.4.0",
"fs-extra": "^8.1.0",
"glob": "^7.1.6",
"gulp": "^4.0.2",

View File

@ -101,6 +101,7 @@ export default function(props: Props) {
const pluginSettings = useMemo(() => {
return pluginService.unserializePluginSettings(props.value);
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [props.value]);
const pluginItems = usePluginItems(pluginService.plugins, pluginSettings);
@ -167,6 +168,7 @@ export default function(props: Props) {
});
props.onChange({ value: pluginService.serializePluginSettings(newSettings) });
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [pluginSettings, props.onChange]);
const onToggle = useCallback((event: ItemEvent) => {
@ -178,6 +180,7 @@ export default function(props: Props) {
});
props.onChange({ value: pluginService.serializePluginSettings(newSettings) });
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [pluginSettings, props.onChange]);
const onInstall = useCallback(async () => {
@ -195,6 +198,7 @@ export default function(props: Props) {
});
props.onChange({ value: pluginService.serializePluginSettings(newSettings) });
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [pluginSettings, props.onChange]);
const onBrowsePlugins = useCallback(() => {
@ -203,6 +207,7 @@ export default function(props: Props) {
const onPluginSettingsChange = useCallback((event: OnPluginSettingChangeEvent) => {
props.onChange({ value: pluginService.serializePluginSettings(event.value) });
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, []);
const onUpdate = useOnInstallHandler(setUpdatingPluginIds, pluginSettings, repoApi, onPluginSettingsChange, true);
@ -229,6 +234,7 @@ export default function(props: Props) {
const onSearchPluginSettingsChange = useCallback((event: any) => {
props.onChange({ value: pluginService.serializePluginSettings(event.value) });
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [props.onChange]);
function renderCells(items: PluginItem[]) {

View File

@ -60,6 +60,7 @@ export default function(props: Props) {
setSearchResultCount(r.length);
}
});
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [props.searchQuery]);
const onChange = useCallback((event: OnChangeEvent) => {
@ -70,6 +71,7 @@ export default function(props: Props) {
const onSearchButtonClick = useCallback(() => {
setSearchStarted(false);
props.onSearchQueryChange({ value: '' });
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, []);
function installState(pluginId: string): InstallState {

View File

@ -57,5 +57,6 @@ export default function(setInstallingPluginIds: Function, pluginSettings: Plugin
});
if (installError) alert(_('Could not install plugin: %s', installError.message));
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [pluginSettings, onPluginSettingsChange]);
}

View File

@ -16,8 +16,10 @@ export default (props: Props) => {
globalKeydownHandlersRef.current.push(elementId);
return () => {
const idx = globalKeydownHandlersRef.current.findIndex(e => e === elementId);
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
globalKeydownHandlersRef.current.splice(idx, 1);
};
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, []);
const isTopDialog = () => {
@ -49,6 +51,7 @@ export default (props: Props) => {
} else if (event.keyCode === 27) {
props.onCancelButtonClick();
}
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [props.onOkButtonClick, props.onCancelButtonClick]);
useEffect(() => {

View File

@ -81,6 +81,7 @@ export default function(props: Props) {
return;
}
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [onClose, folderTitle, folderIcon, props.folderId, props.parentId]);
const onFolderTitleChange = useCallback((event: any) => {

View File

@ -39,6 +39,7 @@ export const ShortcutRecorder = ({ onSave, onReset, onCancel, onError, initialAc
onError({ recorderError });
setSaveAllowed(false);
}
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [accelerator]);
const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {

View File

@ -38,6 +38,7 @@ export default function(props: Props) {
if ([MasterPasswordStatus.NotSet, MasterPasswordStatus.Invalid].includes(status)) return false;
if (mode === Mode.Reset) return false;
return true;
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [status]);
const onClose = useCallback(() => {
@ -84,6 +85,7 @@ export default function(props: Props) {
}
return;
}
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [currentPassword, password1, onClose, mode]);
const needToRepeatPassword = useMemo(() => {

View File

@ -192,12 +192,17 @@ function useMenuStates(menu: any, props: Props) {
clearTimeout(timeoutId);
timeoutId = null;
};
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [
props.menuItemProps,
props.layoutButtonSequence,
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
props['notes.sortOrder.field'],
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
props['folders.sortOrder.field'],
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
props['notes.sortOrder.reverse'],
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
props['folders.sortOrder.reverse'],
props.showNoteCounts,
props.uncompletedTodosOnTop,
@ -276,6 +281,7 @@ function useMenu(props: Props) {
}
void CommandService.instance().execute('hideModalMessage');
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [props.selectedFolderId]);
const onMenuItemClickRef = useRef(null);
@ -292,6 +298,7 @@ function useMenu(props: Props) {
(commandName: string) => onMenuItemClickRef.current(commandName),
props.locale
);
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [commandNames, pluginCommandNames, props.locale]);
const switchProfileMenuItems: any[] = useSwitchProfileMenuItems(props.profileConfig, menuItemDic);
@ -905,13 +912,16 @@ function useMenu(props: Props) {
clearTimeout(timeoutId);
timeoutId = null;
};
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [
props.routeName,
props.pluginMenuItems,
props.pluginMenus,
keymapLastChangeTime,
modulesLastChangeTime,
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
props['spellChecker.language'],
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
props['spellChecker.enabled'],
props.customCss,
props.locale,

View File

@ -70,6 +70,7 @@ export default function NoteContentPropertiesDialog(props: NoteContentProperties
useEffect(() => {
const strippedText: string = markupToHtml().stripMarkup(props.markupLanguage, props.text);
countElements(strippedText, setStrippedWords, setStrippedCharacters, setStrippedCharactersNoSpace, setStrippedLines);
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [props.text]);
useEffect(() => {

View File

@ -259,6 +259,7 @@ function CodeMirror(props: NoteBodyEditorProps, ref: any) {
return commandOutput;
},
};
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [props.content, props.visiblePanes, addListItem, wrapSelectionWithStrings, setEditorPercentScroll, setViewerPercentScroll, resetScroll]);
const onEditorPaste = useCallback(async (event: any = null) => {
@ -565,6 +566,7 @@ function CodeMirror(props: NoteBodyEditorProps, ref: any) {
return () => {
document.head.removeChild(element);
};
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [props.themeId, props.contentMaxWidth]);
const webview_domReady = useCallback(() => {
@ -592,6 +594,7 @@ function CodeMirror(props: NoteBodyEditorProps, ref: any) {
} else {
props.onMessage(event);
}
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [props.onMessage, props.content, setEditorPercentScroll]);
useEffect(() => {
@ -635,6 +638,7 @@ function CodeMirror(props: NoteBodyEditorProps, ref: any) {
cancelled = true;
shim.clearTimeout(timeoutId);
};
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [props.content, props.contentKey, renderedBodyContentKey, props.contentMarkupLanguage, props.visiblePanes, props.resourceInfos, props.markupToHtml]);
useEffect(() => {
@ -660,6 +664,7 @@ function CodeMirror(props: NoteBodyEditorProps, ref: any) {
} else {
console.error('Trying to set HTML on an undefined webview ref');
}
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [renderedBody, webviewReady]);
useEffect(() => {
@ -683,6 +688,7 @@ function CodeMirror(props: NoteBodyEditorProps, ref: any) {
props.setLocalSearchResultCount(matches);
}
}
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [props.searchMarkers, previousSearchMarkers, props.setLocalSearchResultCount, props.content, previousContent, renderedBody, previousRenderedBody, renderedBody]);
const cellEditorStyle = useMemo(() => {
@ -835,6 +841,7 @@ function CodeMirror(props: NoteBodyEditorProps, ref: any) {
return () => {
bridge().window().webContents.off('context-menu', onContextMenu);
};
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [props.plugins]);
function renderEditor() {

View File

@ -219,9 +219,11 @@ function Editor(props: EditorProps, ref: any) {
cm.off('dragover', editor_drag);
cm.off('refresh', editor_resize);
cm.off('update', editor_update);
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
editorParent.current.removeChild(cm.getWrapperElement());
setEditor(null);
};
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, []);
useEffect(() => {
@ -234,36 +236,42 @@ function Editor(props: EditorProps, ref: any) {
}
editor.setOption('screenReaderLabel', props.value);
}
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [props.value]);
useEffect(() => {
if (editor) {
editor.setOption('theme', props.codeMirrorTheme);
}
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [props.codeMirrorTheme]);
useEffect(() => {
if (editor) {
editor.setOption('mode', props.mode);
}
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [props.mode]);
useEffect(() => {
if (editor) {
editor.setOption('readOnly', props.readOnly);
}
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [props.readOnly]);
useEffect(() => {
if (editor) {
editor.setOption('autoCloseBrackets', props.autoMatchBraces);
}
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [props.autoMatchBraces]);
useEffect(() => {
if (editor) {
editor.setOption('keyMap', props.keyMap ? props.keyMap : 'default');
}
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [props.keyMap]);
useEffect(() => {

View File

@ -69,6 +69,7 @@ export default function useExternalPlugins(CodeMirror: any, plugins: PluginState
}
}
setOptions(newOptions);
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [plugins]);
function addInlineCss(cssStrings: string[], id: string) {

View File

@ -184,5 +184,6 @@ export default function useKeymap(CodeMirror: any) {
setupEmacs();
setupVim();
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, []);
}

View File

@ -94,6 +94,7 @@ export default function useScrollHandler(editorRef: any, webviewRef: any, onScro
if (editorRef.current) {
scheduleOnScroll({ percent });
}
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [scheduleOnScroll]);
const setViewerPercentScroll = useCallback((percent: number) => {
@ -101,6 +102,7 @@ export default function useScrollHandler(editorRef: any, webviewRef: any, onScro
webviewRef.current.wrappedInstance.send('setPercentScroll', percent);
scheduleOnScroll({ percent });
}
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [scheduleOnScroll]);
const editor_scroll = useCallback(() => {
@ -126,6 +128,7 @@ export default function useScrollHandler(editorRef: any, webviewRef: any, onScro
lastResizeHeight_.current = NaN;
lastLinesHeight_.current = NaN;
}
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [setViewerPercentScroll]);
const resetScroll = useCallback(() => {
@ -134,6 +137,7 @@ export default function useScrollHandler(editorRef: any, webviewRef: any, onScro
editorRef.current.setScrollPercent(0);
scrollTopIsUncertain_.current = false;
}
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, []);
const editor_resize = useCallback((cm) => {
@ -152,6 +156,7 @@ export default function useScrollHandler(editorRef: any, webviewRef: any, onScro
lastResizeHeight_.current = NaN;
lastLinesHeight_.current = NaN;
}
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, []);
// When heights of lines are updated in CodeMirror, 'update' events are raised.
@ -173,6 +178,7 @@ export default function useScrollHandler(editorRef: any, webviewRef: any, onScro
lastResizeHeight_.current = NaN;
lastLinesHeight_.current = NaN;
}
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, []);
const getLineScrollPercent = useCallback(() => {
@ -183,6 +189,7 @@ export default function useScrollHandler(editorRef: any, webviewRef: any, onScro
} else {
return scrollPercent_.current;
}
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, []);
return {

View File

@ -280,6 +280,7 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => {
return true;
},
};
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [editor, props.contentMarkupLanguage, props.contentOriginalCss]);
// -----------------------------------------------------------------------------------------
@ -512,6 +513,7 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => {
// style and re-applying it on editorReady gives our styles precedence and prevents any flashing
//
// tl;dr: editorReady is used here because the css needs to be re-applied after TinyMCE init
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [editorReady, props.themeId]);
// -----------------------------------------------------------------------------------------
@ -680,6 +682,7 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => {
};
void loadEditor();
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [scriptLoaded]);
// -----------------------------------------------------------------------------------------
@ -829,6 +832,7 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => {
return () => {
cancelled = true;
};
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [editor, props.markupToHtml, props.allAssets, props.content, props.resourceInfos, props.contentKey]);
useEffect(() => {
@ -909,6 +913,7 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => {
return () => {
void execOnChangeEvent();
};
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, []);
const onChangeHandlerTimeoutRef = useRef<any>(null);
@ -1091,6 +1096,7 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => {
console.warn('Error removing events', error);
}
};
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [props.onWillChange, props.onChange, props.contentMarkupLanguage, props.contentOriginalCss, editor]);
// -----------------------------------------------------------------------------------------

View File

@ -59,6 +59,7 @@ function NoteEditor(props: NoteEditorProps) {
const formNote_beforeLoad = useCallback(async (event: OnLoadEvent) => {
await saveNoteIfWillChange(event.formNote);
setShowRevisions(false);
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, []);
const formNote_afterLoad = useCallback(async () => {
@ -177,6 +178,7 @@ function NoteEditor(props: NoteEditorProps) {
id: formNote.id,
});
}
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [props.isProvisional, formNote.id]);
const previousNoteId = usePrevious(formNote.id);
@ -194,6 +196,7 @@ function NoteEditor(props: NoteEditorProps) {
});
void ResourceEditWatcher.instance().stopWatchingAll();
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [formNote.id, previousNoteId]);
const onFieldChange = useCallback((field: string, value: any, changeId = 0) => {
@ -238,6 +241,7 @@ function NoteEditor(props: NoteEditorProps) {
setFormNote(newNote);
scheduleSaveNote(newNote);
}
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [handleProvisionalFlag, formNote, isNewNote, titleHasBeenManuallyChanged]);
useWindowCommandHandler({
@ -288,6 +292,7 @@ function NoteEditor(props: NoteEditorProps) {
id: formNote.id,
status: 'saving',
});
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [formNote, handleProvisionalFlag]);
const onMessage = useMessageHandler(scrollWhenReady, setScrollWhenReady, editorRef, setLocalSearchResultCount, props.dispatch, formNote);
@ -302,6 +307,7 @@ function NoteEditor(props: NoteEditorProps) {
setFormNote(newFormNote);
}
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [formNote]);
const onNotePropertyChange = useCallback((event) => {
@ -317,6 +323,7 @@ function NoteEditor(props: NoteEditorProps) {
return newFormNote;
});
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, []);
useEffect(() => {
@ -350,6 +357,7 @@ function NoteEditor(props: NoteEditorProps) {
noteId: formNoteRef.current.id,
percent: event.percent,
});
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [props.dispatch, formNote]);
function renderNoNotes(rootStyle: any) {

View File

@ -51,5 +51,6 @@ export default function useDropHandler(dependencies: HookDependencies) {
},
});
}
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, []);
}

View File

@ -138,6 +138,7 @@ export default function useFormNote(dependencies: HookDependencies) {
return () => {
cancelled = true;
};
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [prevSyncStarted, syncStarted, formNote]);
useEffect(() => {
@ -188,6 +189,7 @@ export default function useFormNote(dependencies: HookDependencies) {
return () => {
cancelled = true;
};
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [noteId, isProvisional, formNote]);
const onResourceChange = useCallback(async function(event: any = null) {

View File

@ -31,6 +31,7 @@ export default function useMarkupToHtml(deps: HookDependencies) {
resourceBaseUrl: `file://${Setting.value('resourceDir')}/`,
customCss: customCss || '',
});
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [plugins, customCss]);
return useCallback(async (markupLanguage: number, md: string, options: MarkupToHtmlOptions = null): Promise<any> => {
@ -62,5 +63,6 @@ export default function useMarkupToHtml(deps: HookDependencies) {
}, options));
return result;
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [themeId, customCss, markupToHtml]);
}

View File

@ -56,5 +56,6 @@ export default function useMessageHandler(scrollWhenReady: any, setScrollWhenRea
await CommandService.instance().execute('openItem', msg);
// bridge().showErrorMessageBox(_('Unsupported link or message: %s', msg));
}
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [dispatch, setLocalSearchResultCount, scrollWhenReady, formNote]);
}

View File

@ -8,5 +8,6 @@ export default function usePluginServiceRegistration(ref: any) {
return () => {
PlatformImplementation.instance().unregisterComponent('textEditor');
};
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, []);
}

View File

@ -32,5 +32,6 @@ export default function useSearchMarkers(showLocalSearch: boolean, localSearchMa
output.keywords = highlightedWords;
return output;
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [highlightedWords, showLocalSearch, localSearchMarkerOptions, searches, selectedSearchId]);
}

View File

@ -96,5 +96,6 @@ export default function useWindowCommandHandler(dependencies: HookDependencies)
CommandService.instance().unregisterRuntime(command.declaration.name);
}
};
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [editorRef, setShowLocalSearch, noteSearchBarRef, titleInputRef]);
}

View File

@ -273,6 +273,7 @@ const NoteListComponent = (props: Props) => {
onTitleClick={noteItem_titleClick}
onContextMenu={itemContextMenu}
/>;
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [style, props.themeId, width, itemHeight, dragOverTargetNoteIndex, props.provisionalNoteIds, props.selectedNoteIds, props.watchedNoteFiles,
props.notes,
props.notesParentType,
@ -305,6 +306,7 @@ const NoteListComponent = (props: Props) => {
if (previousVisible !== props.visible) {
updateSizeState();
}
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [previousSelectedNoteIds,previousNotes, previousVisible, props.selectedNoteIds, props.notes]);
const scrollNoteIndex_ = (keyCode: any, ctrlKey: any, metaKey: any, noteIndex: any) => {
@ -439,6 +441,7 @@ const NoteListComponent = (props: Props) => {
return () => {
props.resizableLayoutEventEmitter.off('resize', resizableLayout_resize);
};
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [props.resizableLayoutEventEmitter]);
useEffect(() => {
@ -453,6 +456,7 @@ const NoteListComponent = (props: Props) => {
};
}, []);
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
useEffect(() => {
// When a note list item is styled by userchrome.css, its height is reflected.
// Ref. https://github.com/laurent22/joplin/pull/6542

View File

@ -13,5 +13,6 @@ export default function useWindowResizeEvent(eventEmitter: any) {
window_resize.clear();
window.removeEventListener('resize', window_resize);
};
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, []);
}

View File

@ -66,6 +66,7 @@ function useRestartOnDone(upgradeResult: SyncTargetUpgradeResult) {
if (upgradeResult.done && !upgradeResult.error) {
void restart();
}
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [upgradeResult.done]);
}

View File

@ -55,6 +55,7 @@ function SearchBar(props: Props) {
return () => {
debouncedSearch.clear();
};
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [query, searchStarted]);
const onExitSearch = useCallback(async (navigateAway = true) => {
@ -80,6 +81,7 @@ function SearchBar(props: Props) {
}
}
}
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [props.selectedNoteId]);
function onChange(event: any) {
@ -129,6 +131,7 @@ function SearchBar(props: Props) {
field: 'globalSearch',
});
}
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [onExitSearch, props.isFocused, searchStarted]);
useEffect(() => {
@ -150,6 +153,7 @@ function SearchBar(props: Props) {
}
void onExitSearch(true);
}
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, []);
return (

View File

@ -140,6 +140,7 @@ function ShareFolderDialog(props: Props) {
useEffect(() => {
const s = props.shares.find(s => s.folder_id === props.folderId);
setShare(s);
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [props.shares]);
useEffect(() => {

View File

@ -23,5 +23,6 @@ export default function useEffectDebugger(effectHook: any, dependencies: any, de
console.log('[use-effet-debugger] ', changedDeps);
}
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
useEffect(effectHook, dependencies);
}

View File

@ -23,5 +23,6 @@ export default function useImperativeHandleDebugger(ref: any, effectHook: any, d
console.log('[use-imperativeHandler-debugger] ', changedDeps);
}
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
useImperativeHandle(ref, effectHook, dependencies);
}

View File

@ -69,6 +69,7 @@ function UserWebview(props: Props, ref: any) {
useEffect(() => {
if (isReady && props.onReady) props.onReady();
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [isReady]);
function frameWindow() {

View File

@ -33,6 +33,7 @@ export default function(frameWindow: any, htmlHash: string, minWidth: number, mi
useEffect(() => {
updateContentSize(htmlHash);
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [htmlHash]);
useEffect(() => {
@ -55,6 +56,7 @@ export default function(frameWindow: any, htmlHash: string, minWidth: number, mi
return () => {
clearInterval(updateFrameSizeIID);
};
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [fitToContent, isReady, minWidth, minHeight, htmlHash]);
return contentSize;

View File

@ -45,6 +45,7 @@ export default function(frameWindow: any, isReady: boolean, postMessage: Functio
hash: htmlHash,
html: html,
});
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [html, htmlHash, isReady]);
return loadedHtmlHash;

View File

@ -4,10 +4,12 @@ export default function(postMessage: Function, isReady: boolean, scripts: string
useEffect(() => {
if (!isReady) return;
postMessage('setScripts', { scripts: scripts });
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [scripts, isReady]);
useEffect(() => {
if (!isReady || !cssFilePath) return;
postMessage('setScript', { script: cssFilePath, key: 'themeCss' });
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [isReady, cssFilePath]);
}

View File

@ -43,8 +43,10 @@ export default function useViewIsReady(viewRef: any) {
return () => {
viewRef.current.removeEventListener('dom-ready', onIFrameReady);
viewRef.current.removeEventListener('load', onIFrameReady);
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
viewRef.current.contentWindow.removeEventListener('message', onMessage);
};
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, []);
return iframeReady && iframeContentReady;

View File

@ -10,6 +10,7 @@ export default function(frameWindow: any, isReady: boolean, pluginId: string, vi
return () => {
PostMessageService.instance().unregisterResponder(ResponderComponentType.UserWebview, viewId);
};
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [viewId]);
useEffect(() => {
@ -39,5 +40,6 @@ export default function(frameWindow: any, isReady: boolean, pluginId: string, vi
return () => {
frameWindow.removeEventListener('message', onMessage_);
};
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [frameWindow, isReady, pluginId, viewId]);
}

View File

@ -36,5 +36,6 @@ export default function useOnResourceLongPress(onJoplinLinkClick: Function, dial
reg.logger().error('Could not handle link long press', e);
ToastAndroid.show('An error occurred, check log for details', ToastAndroid.SHORT);
}
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [onJoplinLinkClick]);
}

View File

@ -39,6 +39,7 @@ export default function useSource(noteBody: string, noteMarkupLanguage: number,
const markupToHtml = useMemo(() => {
return markupLanguageUtils.newMarkupToHtml();
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [isFirstRender]);
// To address https://github.com/laurent22/joplin/issues/433
@ -202,6 +203,7 @@ export default function useSource(noteBody: string, noteMarkupLanguage: number,
return () => {
cancelled = true;
};
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, effectDependencies);
return { source, injectedJs };

View File

@ -359,8 +359,10 @@ function NoteEditor(props: Props, ref: any) {
} else {
console.info('Unsupported CodeMirror message:', msg);
}
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [props.onChange]);
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
const onError = useCallback(() => {
console.error('NoteEditor: webview error');
});

View File

@ -181,6 +181,7 @@ export const SearchPanel = (props: SearchPanelProps) => {
});
return () => backListener.remove();
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [state.dialogVisible]);

View File

@ -118,6 +118,7 @@ export const useInputMasterPassword = (masterKeys: MasterKeyEntity[], activeMast
if (!(await masterPasswordIsValid(inputMasterPassword, masterKeys.find(mk => mk.id === activeMasterKeyId)))) {
alert('Password is invalid. Please try again.');
}
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [inputMasterPassword]);
const onMasterPasswordChange = useCallback((password: string) => {

View File

@ -14,5 +14,6 @@ export default function(effect: EffectFunction, dependencies: any[]) {
return () => {
event.cancelled = true;
};
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, dependencies);
}

View File

@ -27,7 +27,7 @@ function useElementSize(elementRef: any): Size {
// Initial size on mount
useEffect(() => {
updateSize();
// eslint-disable-next-line react-hooks/exhaustive-deps
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, []);
useEventListener('resize', updateSize);

View File

@ -54,6 +54,7 @@ export default function Page(props: PageProps) {
setError(error);
throw error;
}
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [page, props.scaledSize, isVisible]);
useAsyncEffect(async (event: AsyncEffectEvent) => {
@ -73,6 +74,7 @@ export default function Page(props: PageProps) {
props.container.current.scrollTop = wrapperRef.current.offsetTop;
// console.warn('setting focus on page', props.pageNo, wrapperRef.current.offsetTop);
}
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, [props.focusOnLoad]);
let style: any = {};

View File

@ -29,6 +29,7 @@ const useIsVisible = (elementRef: React.MutableRefObject<HTMLElement>, rootRef:
observer.disconnect();
}
};
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
}, []);
return isVisible;

View File

@ -5969,6 +5969,15 @@ __metadata:
languageName: node
linkType: hard
"@seiyab/eslint-plugin-react-hooks@npm:^4.5.1-alpha.5":
version: 4.5.1-alpha.5
resolution: "@seiyab/eslint-plugin-react-hooks@npm:4.5.1-alpha.5"
peerDependencies:
eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0
checksum: b9840dd3a454c68f6da7b5281d9d4bfe618567b2a2f6228379a9215cffef39eed8d7164dd8f9d809c8a74ea0b8c9e5633dfb747897ae189e5a3e1fede99e6d37
languageName: node
linkType: hard
"@sideway/address@npm:^4.1.3":
version: 4.1.3
resolution: "@sideway/address@npm:4.1.3"
@ -14963,15 +14972,6 @@ __metadata:
languageName: node
linkType: hard
"eslint-plugin-react-hooks@npm:^2.4.0":
version: 2.5.1
resolution: "eslint-plugin-react-hooks@npm:2.5.1"
peerDependencies:
eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0
checksum: a787ea0c665304f3f7249f5528ff1054bd8cfd6b188b95d048ff527b7e54ab7fb10d72254dba1738966e1a8fc4bd2d9fdf8ceb78d205fecbc7f660a334cd512e
languageName: node
linkType: hard
"eslint-plugin-react@npm:^7.18.0":
version: 7.27.1
resolution: "eslint-plugin-react@npm:7.27.1"
@ -29489,6 +29489,7 @@ __metadata:
version: 0.0.0-use.local
resolution: "root@workspace:."
dependencies:
"@seiyab/eslint-plugin-react-hooks": ^4.5.1-alpha.5
"@typescript-eslint/eslint-plugin": ^4.6.0
"@typescript-eslint/parser": ^4.6.0
cspell: ^5.20.0
@ -29496,7 +29497,6 @@ __metadata:
eslint-interactive: ^10.0.0
eslint-plugin-import: ^2.20.2
eslint-plugin-react: ^7.18.0
eslint-plugin-react-hooks: ^2.4.0
fs-extra: ^8.1.0
glob: ^7.1.6
gulp: ^4.0.2