diff --git a/craco.config.js b/craco.config.js index a7ca11e9..fdbde5b4 100644 --- a/craco.config.js +++ b/craco.config.js @@ -13,6 +13,18 @@ module.exports = { eslint: { enable: false, mode: 'file', + rules: { + 'sort-imports': [ + 'error', + { + ignoreCase: false, + ignoreDeclarationSort: false, + ignoreMemberSort: false, + memberSyntaxSortOrder: ['none', 'all', 'multiple', 'single'], + allowSeparatedGroups: false, + }, + ], + }, }, jest: { setupTestFrameworkScriptFile: '/src/setupTests.js', diff --git a/src/components/comment/CommentFormFormatButtons/index.tsx b/src/components/comment/CommentFormFormatButtons/index.tsx index df2d2c0f..f5592cfc 100644 --- a/src/components/comment/CommentFormFormatButtons/index.tsx +++ b/src/components/comment/CommentFormFormatButtons/index.tsx @@ -20,7 +20,7 @@ const CommentFormFormatButtons: FC = ({ element, handler }) => { event.preventDefault(); wrapTextInsideInput(element, '**', '**', handler); }, - [wrap, handler] + [element, handler] ); const wrapItalic = useCallback( @@ -28,7 +28,7 @@ const CommentFormFormatButtons: FC = ({ element, handler }) => { event.preventDefault(); wrapTextInsideInput(element, '*', '*', handler); }, - [wrap, handler] + [element, handler] ); const onKeyPress = useCallback( diff --git a/src/components/containers/InfiniteScroll/index.tsx b/src/components/containers/InfiniteScroll/index.tsx index 70db3103..1fe1ed94 100644 --- a/src/components/containers/InfiniteScroll/index.tsx +++ b/src/components/containers/InfiniteScroll/index.tsx @@ -29,7 +29,7 @@ const InfiniteScroll: FC = ({ children, hasMore, scrollReactPx, loadMore observer.observe(ref.current); return () => observer.disconnect(); - }, [ref.current, onScrollEnd]); + }, [onScrollEnd]); return (
diff --git a/src/components/editors/EditorUploadButton/index.tsx b/src/components/editors/EditorUploadButton/index.tsx index 8553c120..a5198d0a 100644 --- a/src/components/editors/EditorUploadButton/index.tsx +++ b/src/components/editors/EditorUploadButton/index.tsx @@ -34,7 +34,7 @@ const EditorUploadButton: FC = ({ uploadFiles(files); }, - [uploadFiles] + [type, uploadFiles] ); const color = values.is_promoted ? 'primary' : 'lab'; diff --git a/src/components/flow/CellShade/index.tsx b/src/components/flow/CellShade/index.tsx index b97a8471..64874497 100644 --- a/src/components/flow/CellShade/index.tsx +++ b/src/components/flow/CellShade/index.tsx @@ -21,7 +21,7 @@ const CellShade: FC = ({ color, size = 50, ...rest }) => { return `linear-gradient(7deg, ${normalized} ${size}px, ${transparentize(normalized, 1)} ${size * 5}px)`; - }, [color]); + }, [color, size]); return (
diff --git a/src/components/flow/FlowHero/index.tsx b/src/components/flow/FlowHero/index.tsx index 3349fa85..3ae87ca8 100644 --- a/src/components/flow/FlowHero/index.tsx +++ b/src/components/flow/FlowHero/index.tsx @@ -1,11 +1,11 @@ -import React, { FC, useState, useCallback, useEffect, useRef, useMemo } from 'react'; +import React, { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { IFlowState } from '~/redux/flow/reducer'; import classNames from 'classnames'; import styles from './styles.module.scss'; import { getURL } from '~/utils/dom'; -import { withRouter, RouteComponentProps, useHistory } from 'react-router'; -import { URLS, PRESETS } from '~/constants/urls'; +import { RouteComponentProps, useHistory, withRouter } from 'react-router'; +import { PRESETS, URLS } from '~/constants/urls'; import { Icon } from '~/components/input/Icon'; import { INode } from '~/redux/types'; @@ -32,7 +32,7 @@ const FlowHeroUnconnected: FC = ({ heroes }) => { const title = useMemo(() => { return loaded[current]?.title || ''; - }, [loaded, current, heroes]); + }, [loaded, current]); const onNext = useCallback(() => { if (heroes.length > limit) setLimit(limit + 1); @@ -45,16 +45,16 @@ const FlowHeroUnconnected: FC = ({ heroes }) => { const goToNode = useCallback(() => { history.push(URLS.NODE_URL(loaded[current].id)); - }, [current, loaded]); + }, [current, history, loaded]); useEffect(() => { timer.current = setTimeout(onNext, 5000); return () => clearTimeout(timer.current); - }, [current, timer.current]); + }, [current, onNext]); useEffect(() => { if (loaded.length === 1) onNext(); - }, [loaded]); + }, [loaded, onNext]); return (
diff --git a/src/components/flow/FlowStamp/index.tsx b/src/components/flow/FlowStamp/index.tsx index 2e939504..fe8fcf6d 100644 --- a/src/components/flow/FlowStamp/index.tsx +++ b/src/components/flow/FlowStamp/index.tsx @@ -61,7 +61,7 @@ const FlowStamp: FC = ({ ) : ( ), - [searchText] + [onClearSearch, searchText] ); return ( diff --git a/src/components/input/Button/index.tsx b/src/components/input/Button/index.tsx index e0f3965d..aacccad6 100644 --- a/src/components/input/Button/index.tsx +++ b/src/components/input/Button/index.tsx @@ -48,7 +48,7 @@ const Button: FC = memo( has_icon_right: !!iconRight, round, }), - [round, disabled, className, stretchy, iconLeft, iconRight, size, color] + [className, size, color, disabled, stretchy, iconLeft, iconRight, title, children, iconOnly, round] ); return ( diff --git a/src/components/lab/LabBottomPanel/index.tsx b/src/components/lab/LabBottomPanel/index.tsx index 134ec27c..1336c730 100644 --- a/src/components/lab/LabBottomPanel/index.tsx +++ b/src/components/lab/LabBottomPanel/index.tsx @@ -20,7 +20,7 @@ type Props = { const LabBottomPanel: FC = ({ node, hasNewComments, commentCount, isLoading }) => { const history = useHistory(); - const onClick = useCallback(() => history.push(URLS.NODE_URL(node.id)), [node.id]); + const onClick = useCallback(() => history.push(URLS.NODE_URL(node.id)), [history, node.id]); return ( diff --git a/src/components/lab/LabText/index.tsx b/src/components/lab/LabText/index.tsx index 4755ab87..aeeb61ee 100644 --- a/src/components/lab/LabText/index.tsx +++ b/src/components/lab/LabText/index.tsx @@ -9,7 +9,7 @@ import { Paragraph } from '~/components/placeholders/Paragraph'; const LabText: FC = ({ node, isLoading }) => { const content = useMemo(() => formatTextParagraphs(path(['blocks', 0, 'text'], node) || ''), [ - node.blocks, + node, ]); const onClick = useGotoNode(node.id); diff --git a/src/components/main/Header/index.tsx b/src/components/main/Header/index.tsx index 09c8a0c2..f8f26e8d 100644 --- a/src/components/main/Header/index.tsx +++ b/src/components/main/Header/index.tsx @@ -62,7 +62,7 @@ const HeaderUnconnected: FC = memo( useEffect(() => { onScroll(); - }, []); + }, [onScroll]); useEffect(() => { window.addEventListener('scroll', onScroll); @@ -74,7 +74,7 @@ const HeaderUnconnected: FC = memo( is_user && boris_commented_at && (!last_seen_boris || isBefore(new Date(last_seen_boris), new Date(boris_commented_at))), - [boris_commented_at, last_seen_boris] + [boris_commented_at, is_user, last_seen_boris] ); const hasLabUpdates = useMemo(() => labUpdates.length > 0, [labUpdates]); diff --git a/src/components/main/Notifications/index.tsx b/src/components/main/Notifications/index.tsx index d5a04046..cf56bb81 100644 --- a/src/components/main/Notifications/index.tsx +++ b/src/components/main/Notifications/index.tsx @@ -1,4 +1,4 @@ -import React, { FC, useMemo, useState, useCallback, useEffect } from 'react'; +import React, { FC, useCallback, useEffect, useMemo, useState } from 'react'; import { Icon } from '~/components/input/Icon'; import styles from './styles.module.scss'; import { connect } from 'react-redux'; @@ -7,7 +7,7 @@ import { pick } from 'ramda'; import classNames from 'classnames'; import * as AUTH_ACTIONS from '~/redux/auth/actions'; import { NotificationBubble } from '../../notifications/NotificationBubble'; -import { INotification, IMessageNotification } from '~/redux/types'; +import { IMessageNotification, INotification } from '~/redux/types'; const mapStateToProps = state => ({ user: pick(['last_seen_messages'], selectAuthUser(state)), @@ -62,7 +62,7 @@ const NotificationsUnconnected: FC = ({ useEffect(() => { if (!visible || !has_new || !last) return; authSetLastSeenMessages(last); - }, [visible, last]); + }, [visible, last, has_new, authSetLastSeenMessages]); return (
el).join(' - '))) || file.orig_name || '', - [file.metadata] + [file.metadata, file.orig_name] ); const onRename = useCallback( diff --git a/src/components/media/ImagePreloader/index.tsx b/src/components/media/ImagePreloader/index.tsx index 62986b62..0afa1743 100644 --- a/src/components/media/ImagePreloader/index.tsx +++ b/src/components/media/ImagePreloader/index.tsx @@ -44,7 +44,7 @@ const ImagePreloader: FC = ({ file, color, onLoad, onClick, className }) const [width, height] = useMemo( () => [file?.metadata?.width || DEFAULT_WIDTH, file?.metadata?.height || DEFAULT_HEIGHT], - [file?.metadata] + [file] ); useResizeHandler(onResize); diff --git a/src/components/node/CommendDeleted/index.tsx b/src/components/node/CommendDeleted/index.tsx index f6b6a6ef..8b5d3429 100644 --- a/src/components/node/CommendDeleted/index.tsx +++ b/src/components/node/CommendDeleted/index.tsx @@ -9,7 +9,7 @@ interface IProps { } const CommendDeleted: FC = ({ id, onDelete }) => { - const onRestore = useCallback(() => onDelete(id, false), [onDelete]); + const onRestore = useCallback(() => onDelete(id, false), [id, onDelete]); return (
diff --git a/src/components/node/NodeAuthorBlock/index.tsx b/src/components/node/NodeAuthorBlock/index.tsx index d1b1b998..da314400 100644 --- a/src/components/node/NodeAuthorBlock/index.tsx +++ b/src/components/node/NodeAuthorBlock/index.tsx @@ -10,7 +10,7 @@ interface Props { } const NodeAuthorBlock: FC = ({ user }) => { - const onOpenProfile = useCallback(() => openUserProfile(user?.username), [user?.username]); + const onOpenProfile = useCallback(() => openUserProfile(user?.username), [user]); const description = useUserDescription(user); diff --git a/src/components/node/NodeRelatedItem/index.tsx b/src/components/node/NodeRelatedItem/index.tsx index 2428ebfe..c3d6e0d3 100644 --- a/src/components/node/NodeRelatedItem/index.tsx +++ b/src/components/node/NodeRelatedItem/index.tsx @@ -4,10 +4,8 @@ import classNames from 'classnames'; import { INode } from '~/redux/types'; import { PRESETS, URLS } from '~/constants/urls'; import { RouteComponentProps, withRouter } from 'react-router'; -import { getURL, stringToColour } from '~/utils/dom'; +import { getURL } from '~/utils/dom'; import { Avatar } from '~/components/common/Avatar'; -import { normalizeBrightColor } from '~/utils/color'; -import { adjustHue } from 'color2k'; import { useColorGradientFromString } from '~/utils/hooks/useColorGradientFromString'; type IProps = RouteComponentProps & { @@ -53,7 +51,7 @@ const NodeRelatedItemUnconnected: FC = memo(({ item, history }) => { cb(); return () => window.removeEventListener('resize', cb); - }, [ref.current]); + }, []); const size = useMemo(() => { if (width > 90) return 'large'; diff --git a/src/components/node/NodeTextBlock/index.tsx b/src/components/node/NodeTextBlock/index.tsx index 47abb33c..206e0202 100644 --- a/src/components/node/NodeTextBlock/index.tsx +++ b/src/components/node/NodeTextBlock/index.tsx @@ -9,9 +9,7 @@ import markdown from '~/styles/common/markdown.module.scss'; interface IProps extends INodeComponentProps {} const NodeTextBlock: FC = ({ node }) => { - const content = useMemo(() => formatTextParagraphs(path(['blocks', 0, 'text'], node) || ''), [ - node.blocks, - ]); + const content = useMemo(() => formatTextParagraphs(path(['blocks', 0, 'text'], node) || ''), [node]); return (
= ({ useEffect(() => { authSetProfile({ patch_errors: {} }); - }, [password, new_password, data]); + }, [password, new_password, data, authSetProfile]); return (
diff --git a/src/components/tags/TagAutocomplete/index.tsx b/src/components/tags/TagAutocomplete/index.tsx index 2dd80338..ff783313 100644 --- a/src/components/tags/TagAutocomplete/index.tsx +++ b/src/components/tags/TagAutocomplete/index.tsx @@ -83,7 +83,7 @@ const TagAutocompleteUnconnected: FC = ({ useEffect(() => { setSelected(-1); tagLoadAutocomplete(search, exclude); - }, [search]); + }, [exclude, search, tagLoadAutocomplete]); useEffect(() => { tagSetAutocomplete({ options: [] }); @@ -102,7 +102,7 @@ const TagAutocompleteUnconnected: FC = ({ if (clientHeight - scrollTop + el.clientHeight < offsetTop || offsetTop < scrollTop) { scroll.current.scrollTo(0, el.offsetTop - el.clientHeight); } - }, [selected, scroll.current]); + }, [selected]); return (
= ({ exclude, onAppend, onClearTag, onSubmit }) => { setInput(items[items.length - 1] || ''); }, - [setInput] + [onAppend] ); const onKeyDown = useCallback( @@ -71,7 +71,7 @@ const TagInput: FC = ({ exclude, onAppend, onClearTag, onSubmit }) => { setInput(''); } }, - [input, setInput, onClearTag, onAppend, onSubmit, ref.current, wrapper.current] + [input, setInput, onClearTag, onAppend] ); const onFocus = useCallback(() => setFocused(true), []); @@ -94,7 +94,7 @@ const TagInput: FC = ({ exclude, onAppend, onClearTag, onSubmit }) => { onSubmit([]); }, - [input, onAppend, setInput, onSubmit] + [input, setInput, onSubmit] ); const onAutocompleteSelect = useCallback( diff --git a/src/components/tags/Tags/index.tsx b/src/components/tags/Tags/index.tsx index 0f4acf4b..7b5479b0 100644 --- a/src/components/tags/Tags/index.tsx +++ b/src/components/tags/Tags/index.tsx @@ -43,12 +43,12 @@ export const Tags: FC = ({ onTagsChange(uniqueTags); }, - [data] + [data, onTagsChange, tags] ); useEffect(() => { setData(data.filter(title => !tags.some(tag => tag?.title?.trim() === title.trim()))); - }, [tags]); + }, [data, tags]); const onAppendTag = useCallback( (created: string[]) => { diff --git a/src/components/upload/UploadDropzone/index.tsx b/src/components/upload/UploadDropzone/index.tsx index 508f9062..a4e70e8f 100644 --- a/src/components/upload/UploadDropzone/index.tsx +++ b/src/components/upload/UploadDropzone/index.tsx @@ -19,7 +19,7 @@ const UploadDropzone: FC = ({ children, onUpload, helperClassName, ...re onStopDragging(); onUpload(files); }, - [onUpload] + [onStopDragging, onUpload] ); return ( diff --git a/src/constants/phrases.ts b/src/constants/phrases.ts index 638dc386..0f283477 100644 --- a/src/constants/phrases.ts +++ b/src/constants/phrases.ts @@ -64,4 +64,4 @@ export const PHRASES = { }; export const useRandomPhrase = (key: keyof typeof PHRASES) => - useMemo(() => PHRASES[key][Math.floor(Math.random() * PHRASES[key].length)], []); + useMemo(() => PHRASES[key][Math.floor(Math.random() * PHRASES[key].length)], [key]); diff --git a/src/containers/dialogs/EditorDialog/index.tsx b/src/containers/dialogs/EditorDialog/index.tsx index 3ad3d045..8be7e5af 100644 --- a/src/containers/dialogs/EditorDialog/index.tsx +++ b/src/containers/dialogs/EditorDialog/index.tsx @@ -15,7 +15,6 @@ import { ModalWrapper } from '~/components/dialogs/ModalWrapper'; import { useTranslatedError } from '~/utils/hooks/useTranslatedError'; import { useCloseOnEscape } from '~/utils/hooks'; import { EditorConfirmClose } from '~/components/editors/EditorConfirmClose'; -import { UploadDropzone } from '~/components/upload/UploadDropzone'; interface Props extends IDialogProps { node: INode; @@ -46,7 +45,7 @@ const EditorDialog: FC = ({ node, onRequestClose }) => { } setConfirmModalShown(true); - }, [onRequestClose, dirty, isConfirmModalShown, setConfirmModalShown]); + }, [dirty, isConfirmModalShown, onRequestClose, closeConfirmModal]); const error = useTranslatedError(status); @@ -56,7 +55,7 @@ const EditorDialog: FC = ({ node, onRequestClose }) => { } setStatus(''); - }, [values]); + }, [setStatus, status, values]); useCloseOnEscape(onClose); diff --git a/src/containers/dialogs/LoginDialog/index.tsx b/src/containers/dialogs/LoginDialog/index.tsx index 9aa7d12b..8262aa6f 100644 --- a/src/containers/dialogs/LoginDialog/index.tsx +++ b/src/containers/dialogs/LoginDialog/index.tsx @@ -1,4 +1,4 @@ -import React, { FC, FormEvent, useCallback, useEffect, useMemo, useState } from 'react'; +import React, { FC, FormEvent, useCallback, useEffect, useState } from 'react'; import { connect } from 'react-redux'; import { DIALOGS, IDialogProps } from '~/redux/modal/constants'; import { useCloseOnEscape } from '~/utils/hooks'; @@ -18,7 +18,6 @@ import { pick } from 'ramda'; import { LoginDialogButtons } from '~/containers/dialogs/LoginDialogButtons'; import { OAUTH_EVENT_TYPES } from '~/redux/types'; import { DialogTitle } from '~/components/dialogs/DialogTitle'; -import { ERROR_LITERAL } from '~/constants/errors'; import { useTranslatedError } from '~/utils/hooks/useTranslatedError'; const mapStateToProps = state => ({ @@ -60,7 +59,7 @@ const LoginDialogUnconnected: FC = ({ event.preventDefault(); modalShowDialog(DIALOGS.RESTORE_REQUEST); }, - [modalShowDialog, userSetLoginError] + [modalShowDialog] ); const openOauthWindow = useCallback( @@ -83,7 +82,7 @@ const LoginDialogUnconnected: FC = ({ useEffect(() => { if (error) userSetLoginError(''); - }, [username, password]); + }, [username, password, error, userSetLoginError]); useEffect(() => { window.addEventListener('message', onMessage); diff --git a/src/containers/dialogs/LoginSocialRegisterDialog/index.tsx b/src/containers/dialogs/LoginSocialRegisterDialog/index.tsx index ff210210..658d9fbc 100644 --- a/src/containers/dialogs/LoginSocialRegisterDialog/index.tsx +++ b/src/containers/dialogs/LoginSocialRegisterDialog/index.tsx @@ -51,15 +51,15 @@ const LoginSocialRegisterDialogUnconnected: FC = ({ useEffect(() => { if (errors.username) authSetRegisterSocialErrors({ username: '' }); - }, [username]); + }, [authSetRegisterSocialErrors, errors.username, username]); useEffect(() => { if (errors.password) authSetRegisterSocialErrors({ password: '' }); - }, [password]); + }, [authSetRegisterSocialErrors, errors.password, password]); useEffect(() => { if (error) authSetRegisterSocial({ error: '' }); - }, [username, password]); + }, [username, password, error, authSetRegisterSocial]); useCloseOnEscape(onRequestClose); diff --git a/src/containers/dialogs/PhotoSwipe/index.tsx b/src/containers/dialogs/PhotoSwipe/index.tsx index 2bff3622..e0ef6d33 100644 --- a/src/containers/dialogs/PhotoSwipe/index.tsx +++ b/src/containers/dialogs/PhotoSwipe/index.tsx @@ -66,7 +66,7 @@ const PhotoSwipeUnconnected: FC = ({ photoswipe, modalSetShown }) => { ps.listen('destroy', closeModal); ps.listen('close', closeModal); }); - }, [photoswipe.images, photoswipe.index]); + }, [closeModal, photoswipe.images, photoswipe.index]); useBlockBackButton(closeModal); diff --git a/src/containers/dialogs/RestorePasswordDialog/index.tsx b/src/containers/dialogs/RestorePasswordDialog/index.tsx index d768b1ba..b47ab5f1 100644 --- a/src/containers/dialogs/RestorePasswordDialog/index.tsx +++ b/src/containers/dialogs/RestorePasswordDialog/index.tsx @@ -44,14 +44,14 @@ const RestorePasswordDialogUnconnected: FC = ({ authRestorePassword(password); }, - [doesnt_match, authRestorePassword] + [doesnt_match, authRestorePassword, password] ); useEffect(() => { if (error || is_succesfull) { authSetRestore({ error: '', is_succesfull: false }); } - }, [password, password_again]); + }, [authSetRestore, error, is_succesfull, password, password_again]); const buttons = useMemo( () => ( @@ -80,7 +80,7 @@ const RestorePasswordDialogUnconnected: FC = ({ ) : ( undefined ), - [is_succesfull] + [is_succesfull, onRequestClose, user] ); const not_ready = useMemo( @@ -105,7 +105,7 @@ const RestorePasswordDialogUnconnected: FC = ({ ) : ( undefined ), - [is_loading, user, error] + [is_loading, user, error, onRequestClose] ); useCloseOnEscape(onRequestClose); diff --git a/src/containers/dialogs/RestoreRequestDialog/index.tsx b/src/containers/dialogs/RestoreRequestDialog/index.tsx index 616bd55c..3e1c7fd1 100644 --- a/src/containers/dialogs/RestoreRequestDialog/index.tsx +++ b/src/containers/dialogs/RestoreRequestDialog/index.tsx @@ -1,4 +1,4 @@ -import React, { FC, useState, useMemo, useCallback, useEffect } from 'react'; +import React, { FC, useCallback, useEffect, useMemo, useState } from 'react'; import { IDialogProps } from '~/redux/types'; import { connect } from 'react-redux'; import { BetterScrollDialog } from '../BetterScrollDialog'; @@ -45,7 +45,7 @@ const RestoreRequestDialogUnconnected: FC = ({ if (error || is_succesfull) { authSetRestore({ error: '', is_succesfull: false }); } - }, [field]); + }, [authSetRestore, error, field, is_succesfull]); const buttons = useMemo( () => ( @@ -75,7 +75,7 @@ const RestoreRequestDialogUnconnected: FC = ({ ) : ( undefined ), - [is_succesfull] + [is_succesfull, onRequestClose] ); useCloseOnEscape(onRequestClose); diff --git a/src/containers/lab/LabGrid/index.tsx b/src/containers/lab/LabGrid/index.tsx index 7dcf0ba6..4119936a 100644 --- a/src/containers/lab/LabGrid/index.tsx +++ b/src/containers/lab/LabGrid/index.tsx @@ -31,10 +31,7 @@ const LoadingNode = () => ( ); const LabGrid: FC = ({ isLoading, nodes, onLoadMore }) => { - const columns = useMemo(() => Array.from(document.querySelectorAll(`.${styles.column}`)), [ - isLoading, - nodes, - ]); + const columns = useMemo(() => Array.from(document.querySelectorAll(`.${styles.column}`)), []); useLabPagination(isLoading, columns, onLoadMore); diff --git a/src/containers/profile/ProfileLayout/index.tsx b/src/containers/profile/ProfileLayout/index.tsx index bf1f9072..f66bece2 100644 --- a/src/containers/profile/ProfileLayout/index.tsx +++ b/src/containers/profile/ProfileLayout/index.tsx @@ -24,7 +24,7 @@ const ProfileLayoutUnconnected: FC = ({ history, nodeSetCoverImage }) => useEffect(() => { if (user) setUser(undefined); - }, [username]); + }, [user, username]); useEffect(() => { if (user && user.id && user.cover) { @@ -33,7 +33,7 @@ const ProfileLayoutUnconnected: FC = ({ history, nodeSetCoverImage }) => nodeSetCoverImage(undefined); }; } - }, [user]); + }, [nodeSetCoverImage, user]); return ( diff --git a/src/containers/profile/ProfileMessages/index.tsx b/src/containers/profile/ProfileMessages/index.tsx index 92357851..804e6c04 100644 --- a/src/containers/profile/ProfileMessages/index.tsx +++ b/src/containers/profile/ProfileMessages/index.tsx @@ -47,7 +47,7 @@ const ProfileMessagesUnconnected: FC = ({ if (profile.is_loading || !profile.user || !profile.user.username) return; messagesGetMessages(profile.user.username); - }, [profile.user]); + }, [messagesGetMessages, profile.is_loading, profile.user]); useEffect(() => { const timer = setInterval(messagesRefreshMessages, 20000); @@ -73,7 +73,7 @@ const ProfileMessagesUnconnected: FC = ({ if (wasAtBottom.current) { parent.scrollTo(0, parent.scrollHeight); } - }, [messages.messages]); + }, [messages.messages, wrap]); const onScroll = useCallback(() => { const parent = wrap?.parentElement; diff --git a/src/containers/sidebars/ProfileSidebar/index.tsx b/src/containers/sidebars/ProfileSidebar/index.tsx index 9032856d..0d8195bc 100644 --- a/src/containers/sidebars/ProfileSidebar/index.tsx +++ b/src/containers/sidebars/ProfileSidebar/index.tsx @@ -1,4 +1,4 @@ -import React, { FC, useCallback, useEffect, useState } from 'react'; +import React, { FC, useCallback, useEffect } from 'react'; import styles from './styles.module.scss'; import { SidebarWrapper } from '~/containers/sidebars/SidebarWrapper'; import { connect } from 'react-redux'; @@ -37,11 +37,11 @@ const ProfileSidebarUnconnected: FC = ({ useEffect(() => { authLoadProfile(username); - }, [username]); + }, [authLoadProfile, username]); const history = useHistory(); const basePath = url.replace(new RegExp(`\/~${username}$`), ''); - const onClose = useCallback(() => history.push(basePath), [basePath]); + const onClose = useCallback(() => history.push(basePath), [basePath, history]); useCloseOnEscape(onClose); diff --git a/src/containers/sidebars/SidebarWrapper/index.tsx b/src/containers/sidebars/SidebarWrapper/index.tsx index 22337760..fb16af23 100644 --- a/src/containers/sidebars/SidebarWrapper/index.tsx +++ b/src/containers/sidebars/SidebarWrapper/index.tsx @@ -1,7 +1,7 @@ import React, { FC, useEffect, useRef } from 'react'; import styles from './styles.module.scss'; import { createPortal } from 'react-dom'; -import { disableBodyScroll, clearAllBodyScrollLocks } from 'body-scroll-lock'; +import { clearAllBodyScrollLocks, disableBodyScroll } from 'body-scroll-lock'; import { useCloseOnEscape } from '~/utils/hooks'; interface IProps { @@ -18,7 +18,7 @@ const SidebarWrapper: FC = ({ children, onClose }) => { disableBodyScroll(ref.current, { reserveScrollBarGap: true }); return () => clearAllBodyScrollLocks(); - }, [ref.current]); + }, []); return createPortal(
diff --git a/src/containers/sidebars/TagSidebar/index.tsx b/src/containers/sidebars/TagSidebar/index.tsx index ff045a81..559dee4f 100644 --- a/src/containers/sidebars/TagSidebar/index.tsx +++ b/src/containers/sidebars/TagSidebar/index.tsx @@ -31,7 +31,7 @@ const TagSidebarUnconnected: FC = ({ nodes, tagLoadNodes, tagSetNodes }) const history = useHistory(); const basePath = url.replace(new RegExp(`\/tag\/${tag}$`), ''); - const onClose = useCallback(() => history.push(basePath), [basePath]); + const onClose = useCallback(() => history.push(basePath), [basePath, history]); useEffect(() => { tagLoadNodes(tag); @@ -39,7 +39,7 @@ const TagSidebarUnconnected: FC = ({ nodes, tagLoadNodes, tagSetNodes }) return () => { tagSetNodes({ list: [], count: 0 }); }; - }, [tag]); + }, [tag, tagLoadNodes, tagSetNodes]); const loadMore = useCallback(() => { if (nodes.isLoading) return; diff --git a/src/layouts/ProfileLayout/index.tsx b/src/layouts/ProfileLayout/index.tsx index 4412a23b..bcd70fa5 100644 --- a/src/layouts/ProfileLayout/index.tsx +++ b/src/layouts/ProfileLayout/index.tsx @@ -27,7 +27,7 @@ const ProfileLayout: FC = ({ useEffect(() => { dispatch(authLoadProfile(username)); - }, [username]); + }, [dispatch, username]); const profile = useShallowSelect(selectAuthProfile); diff --git a/src/pages/boris.tsx b/src/pages/boris.tsx index fe6381f5..5ceb949f 100644 --- a/src/pages/boris.tsx +++ b/src/pages/boris.tsx @@ -25,7 +25,7 @@ const BorisPage: VFC = () => { useEffect(() => { if (node.is_loading) return; dispatch(nodeLoadNode(696, 'DESC')); - }, [dispatch]); + }, [dispatch, node.is_loading]); return ( { const onChangeCellView = useCallback( (id: INode['id'], val: FlowDisplay) => dispatch(flowSetCellView(id, val)), - [] + [dispatch] ); return { nodes, heroes, recent, updates, isFluid, toggleLayout, onChangeCellView }; diff --git a/src/utils/hooks/flow/useFlowCellControls.ts b/src/utils/hooks/flow/useFlowCellControls.ts index 28124dfa..dc8f95fe 100644 --- a/src/utils/hooks/flow/useFlowCellControls.ts +++ b/src/utils/hooks/flow/useFlowCellControls.ts @@ -9,7 +9,7 @@ export const useFlowCellControls = ( ) => { const onChange = useCallback( (value: Partial) => onChangeCellView(id, { ...flow, ...value }), - [flow, onChangeCellView] + [flow, id, onChangeCellView] ); const hasDescription = !!description && description.length > 32; diff --git a/src/utils/hooks/flow/useFlowPagination.ts b/src/utils/hooks/flow/useFlowPagination.ts index bb88461c..de0b6c15 100644 --- a/src/utils/hooks/flow/useFlowPagination.ts +++ b/src/utils/hooks/flow/useFlowPagination.ts @@ -1,10 +1,10 @@ -import { useCallback, useEffect } from 'react'; +import { useCallback } from 'react'; import { flowGetMore } from '~/redux/flow/actions'; import { useDispatch } from 'react-redux'; import { useInfiniteLoader } from '~/utils/hooks/useInfiniteLoader'; export const useFlowPagination = ({ isLoading }) => { const dispatch = useDispatch(); - const loadMore = useCallback(() => dispatch(flowGetMore()), []); + const loadMore = useCallback(() => dispatch(flowGetMore()), [dispatch]); useInfiniteLoader(loadMore, isLoading); }; diff --git a/src/utils/hooks/index.ts b/src/utils/hooks/index.ts index 64e3f3c5..148284c3 100644 --- a/src/utils/hooks/index.ts +++ b/src/utils/hooks/index.ts @@ -53,6 +53,6 @@ export const useFileDropZone = (onUpload: (file: File[]) => void, allowedTypes?: onUpload(files); }, - [onUpload] + [allowedTypes, onUpload] ); }; diff --git a/src/utils/hooks/lab/useLabPagination.ts b/src/utils/hooks/lab/useLabPagination.ts index c9262fe1..af71b7b0 100644 --- a/src/utils/hooks/lab/useLabPagination.ts +++ b/src/utils/hooks/lab/useLabPagination.ts @@ -40,5 +40,5 @@ export const useLabPagination = ( return () => { lastItems.forEach(item => observer.unobserve(item)); }; - }, [observer, columns]); + }, [observer, columns, isLoading]); }; diff --git a/src/utils/hooks/node/useGotoNode.ts b/src/utils/hooks/node/useGotoNode.ts index bee8e7c2..7d3c294c 100644 --- a/src/utils/hooks/node/useGotoNode.ts +++ b/src/utils/hooks/node/useGotoNode.ts @@ -6,5 +6,5 @@ import { URLS } from '~/constants/urls'; // useGotoNode returns fn, that navigates to node export const useGotoNode = (id: INode['id']) => { const history = useHistory(); - return useCallback(() => history.push(URLS.NODE_URL(id)), [id]); + return useCallback(() => history.push(URLS.NODE_URL(id)), [history, id]); }; diff --git a/src/utils/hooks/node/useGrouppedComments.ts b/src/utils/hooks/node/useGrouppedComments.ts index c924a6ec..bf38f178 100644 --- a/src/utils/hooks/node/useGrouppedComments.ts +++ b/src/utils/hooks/node/useGrouppedComments.ts @@ -13,5 +13,5 @@ export const useGrouppedComments = ( groupCommentsByUser(lastSeen), [] ), - [comments, order] + [comments, lastSeen, order] ); diff --git a/src/utils/hooks/node/useLoadNode.ts b/src/utils/hooks/node/useLoadNode.ts index 600fa0a2..af98e7a6 100644 --- a/src/utils/hooks/node/useLoadNode.ts +++ b/src/utils/hooks/node/useLoadNode.ts @@ -14,5 +14,5 @@ export const useLoadNode = (id: any, isLoading: boolean) => { return () => { dispatch(nodeSetCurrent(EMPTY_NODE)); }; - }, [dispatch, id]); + }, [dispatch, id, isLoading]); }; diff --git a/src/utils/hooks/node/useNodeActions.ts b/src/utils/hooks/node/useNodeActions.ts index cd3bb124..389ed94a 100644 --- a/src/utils/hooks/node/useNodeActions.ts +++ b/src/utils/hooks/node/useNodeActions.ts @@ -6,14 +6,10 @@ import { nodeEdit, nodeLike, nodeLock, nodeStar } from '~/redux/node/actions'; export const useNodeActions = (node: INode) => { const dispatch = useDispatch(); - const onEdit = useCallback(() => dispatch(nodeEdit(node.id)), [dispatch, nodeEdit, node]); - const onLike = useCallback(() => dispatch(nodeLike(node.id)), [dispatch, nodeLike, node]); - const onStar = useCallback(() => dispatch(nodeStar(node.id)), [dispatch, nodeStar, node]); - const onLock = useCallback(() => dispatch(nodeLock(node.id, !node.deleted_at)), [ - dispatch, - nodeLock, - node, - ]); + const onEdit = useCallback(() => dispatch(nodeEdit(node.id)), [dispatch, node]); + const onLike = useCallback(() => dispatch(nodeLike(node.id)), [dispatch, node]); + const onStar = useCallback(() => dispatch(nodeStar(node.id)), [dispatch, node]); + const onLock = useCallback(() => dispatch(nodeLock(node.id, !node.deleted_at)), [dispatch, node]); return { onEdit, onLike, onStar, onLock }; }; diff --git a/src/utils/hooks/useBlockBackButton.ts b/src/utils/hooks/useBlockBackButton.ts index f914368d..b8dd07aa 100644 --- a/src/utils/hooks/useBlockBackButton.ts +++ b/src/utils/hooks/useBlockBackButton.ts @@ -19,6 +19,6 @@ export const useBlockBackButton = (callback?: () => void) => { callback(); } }), - [callback, history] + [callback] ); }; diff --git a/src/utils/hooks/useClickOutsideFocus.ts b/src/utils/hooks/useClickOutsideFocus.ts index a6239ecf..17500715 100644 --- a/src/utils/hooks/useClickOutsideFocus.ts +++ b/src/utils/hooks/useClickOutsideFocus.ts @@ -25,7 +25,7 @@ export const useClickOutsideFocus = () => { document.addEventListener('mouseup', deactivator); return () => document.removeEventListener('mouseup', deactivator); - }, [isActive]); + }, [deactivate, isActive]); useCloseOnEscape(deactivate); diff --git a/src/utils/hooks/useColorFromString.ts b/src/utils/hooks/useColorFromString.ts index 90208506..67e8ec9a 100644 --- a/src/utils/hooks/useColorFromString.ts +++ b/src/utils/hooks/useColorFromString.ts @@ -5,6 +5,6 @@ import { stringToColour } from '~/utils/dom'; export const useColorFromString = (val?: string, saturation = 3, lightness = 3) => { return useMemo( () => (val && normalizeBrightColor(stringToColour(val), saturation, lightness)) || '', - [] + [lightness, saturation, val] ); }; diff --git a/src/utils/hooks/useColorGradientFromString.ts b/src/utils/hooks/useColorGradientFromString.ts index 06536d7f..164ccab1 100644 --- a/src/utils/hooks/useColorGradientFromString.ts +++ b/src/utils/hooks/useColorGradientFromString.ts @@ -19,4 +19,4 @@ export const useColorGradientFromString = ( const third = normalizeBrightColor(adjustHue(color, 90), saturation, lightness); return `linear-gradient(${angle}deg, ${color}, ${second}, ${third})`; - }, [val]); + }, [angle, lightness, saturation, val]); diff --git a/src/utils/hooks/useCommentFormFormik.ts b/src/utils/hooks/useCommentFormFormik.ts index 24592101..5b666a15 100644 --- a/src/utils/hooks/useCommentFormFormik.ts +++ b/src/utils/hooks/useCommentFormFormik.ts @@ -71,7 +71,7 @@ export const useCommentFormFormik = ( if (formik.status) { formik.setStatus(''); } - }, [formik.values.text]); + }, [formik, formik.values.text]); return formik; }; diff --git a/src/utils/hooks/useDragDetector.tsx b/src/utils/hooks/useDragDetector.tsx index 80760d68..890a68e1 100644 --- a/src/utils/hooks/useDragDetector.tsx +++ b/src/utils/hooks/useDragDetector.tsx @@ -1,5 +1,4 @@ -import React, { FC, useContext } from 'react'; -import { createContext, useCallback, useEffect, useState } from 'react'; +import React, { createContext, FC, useCallback, useContext, useEffect, useState } from 'react'; const DragContext = createContext({ isDragging: false, @@ -44,7 +43,7 @@ export const useDragDetector = () => { document.removeEventListener('blur', removeClass); document.removeEventListener('drop', onStopDragging); }; - }, [setIsDragging]); + }, [onStopDragging, setIsDragging]); return { isDragging, onStopDragging }; }; diff --git a/src/utils/hooks/useInputPasteUpload.ts b/src/utils/hooks/useInputPasteUpload.ts index dff574a1..b4574cf2 100644 --- a/src/utils/hooks/useInputPasteUpload.ts +++ b/src/utils/hooks/useInputPasteUpload.ts @@ -12,7 +12,7 @@ export const useInputPasteUpload = ( if (!image) return; onUpload([image]); - }, []); + }, [onUpload]); useEffect(() => { if (!input) return; diff --git a/src/utils/hooks/useNodeFormFormik.ts b/src/utils/hooks/useNodeFormFormik.ts index f570811e..851a1cb2 100644 --- a/src/utils/hooks/useNodeFormFormik.ts +++ b/src/utils/hooks/useNodeFormFormik.ts @@ -1,8 +1,8 @@ -import { IComment, INode } from '~/redux/types'; +import { INode } from '~/redux/types'; import { FileUploader } from '~/utils/hooks/useFileUploader'; import { useCallback, useEffect, useRef } from 'react'; import { FormikHelpers, useFormik, useFormikContext } from 'formik'; -import { object, string } from 'yup'; +import { object } from 'yup'; import { useDispatch } from 'react-redux'; import { nodeSubmitLocal } from '~/redux/node/actions'; import { keys } from 'ramda'; @@ -39,7 +39,7 @@ export const useNodeFormFormik = ( const onSubmit = useCallback((values: INode, helpers: FormikHelpers) => { helpers.setSubmitting(true); dispatch(nodeSubmitLocal(values, onSuccess(helpers))); - }, []); + }, [dispatch]); const { current: initialValues } = useRef(values); @@ -60,7 +60,7 @@ export const useNodeFormFormik = ( useEffect(() => { formik.setFieldValue('files', uploader.files); - }, [formik.setFieldValue, uploader.files]); + }, [formik, formik.setFieldValue, uploader.files]); return formik; };