Skip to content

Commit 5f98341

Browse files
committed
fix(eslint): resolve react-hooks violations
1 parent 40f46e7 commit 5f98341

File tree

9 files changed

+68
-70
lines changed

9 files changed

+68
-70
lines changed

src/components/Article/ActionButtons.jsx

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import {
1818
IconStarFill,
1919
} from "@arco-design/web-react/icon"
2020
import { useStore } from "@nanostores/react"
21-
import { memo, useEffect, useState } from "react"
21+
import { memo, useState } from "react"
2222

2323
import ArticleTOC from "./ArticleTOC"
2424

@@ -99,6 +99,13 @@ const ActionButtons = () => {
9999

100100
const [dropdownVisible, setDropdownVisible] = useState(false)
101101
const [isFetchedOriginal, setIsFetchedOriginal] = useState(false)
102+
const [lastActiveContentId, setLastActiveContentId] = useState(activeContent?.id)
103+
104+
if (activeContent?.id !== lastActiveContentId) {
105+
setLastActiveContentId(activeContent?.id)
106+
setIsFetchedOriginal(false)
107+
}
108+
102109
const hasHeadings = headings.length > 0
103110

104111
const {
@@ -396,10 +403,6 @@ const ActionButtons = () => {
396403
),
397404
}
398405

399-
useEffect(() => {
400-
setIsFetchedOriginal(false)
401-
}, [activeContent])
402-
403406
return (
404407
<div className={`action-buttons ${isBelowMedium ? "mobile" : ""}`}>
405408
{isBelowMedium ? (

src/components/Article/SearchAndSortBar.jsx

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -41,21 +41,13 @@ const handleFilterTypeChange = (value) => {
4141
setFilterType(value)
4242
}
4343

44-
const SearchModal = memo(({ initialValue, visible, onCancel, onConfirm }) => {
44+
const SearchModal = memo(({ value, visible, onCancel, onConfirm, onChange }) => {
4545
const { filterType } = useStore(contentState)
4646
const { polyglot } = useStore(polyglotState)
4747
const tooltipLines = polyglot.t("search.tooltip").split("\n")
4848

49-
const [inputValue, setInputValue] = useState(initialValue)
50-
51-
useEffect(() => {
52-
if (visible) {
53-
setInputValue(initialValue)
54-
}
55-
}, [initialValue, visible])
56-
5749
const handleConfirm = () => {
58-
onConfirm(inputValue)
50+
onConfirm(value)
5951
}
6052

6153
const handleKeyDown = (event) => {
@@ -83,7 +75,7 @@ const SearchModal = memo(({ initialValue, visible, onCancel, onConfirm }) => {
8375
<Input.Search
8476
allowClear
8577
placeholder={polyglot.t("search.placeholder")}
86-
value={inputValue}
78+
value={value}
8779
addBefore={
8880
<Select
8981
style={{ width: "auto" }}
@@ -117,7 +109,7 @@ const SearchModal = memo(({ initialValue, visible, onCancel, onConfirm }) => {
117109
<IconQuestionCircle />
118110
</Tooltip>
119111
}
120-
onChange={setInputValue}
112+
onChange={onChange}
121113
onKeyDown={handleKeyDown}
122114
/>
123115
</div>
@@ -297,9 +289,10 @@ const SearchAndSortBar = () => {
297289
</CustomTooltip>
298290
</div>
299291
<SearchModal
300-
initialValue={modalInputValue}
292+
value={modalInputValue}
301293
visible={searchModalVisible}
302294
onCancel={closeSearchModal}
295+
onChange={setModalInputValue}
303296
onConfirm={handleConfirmSearch}
304297
/>
305298
</div>

src/components/Article/SidebarTrigger.jsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,23 @@
11
import { Button, Drawer } from "@arco-design/web-react"
22
import { IconMenu } from "@arco-design/web-react/icon"
3-
import { useEffect, useState } from "react"
3+
import { useStore } from "@nanostores/react"
4+
import { atom } from "nanostores"
5+
import { useEffect } from "react"
46
import { useLocation } from "react-router"
57

68
import Sidebar from "@/components/Sidebar/Sidebar"
79
import useScreenWidth from "@/hooks/useScreenWidth"
810
import "./SidebarTrigger.css"
11+
import createSetter from "@/utils/nanostores"
12+
13+
const sidebarVisibleState = atom(false)
14+
const setSidebarVisible = createSetter(sidebarVisibleState)
915

1016
export default function SidebarTrigger() {
1117
const currentPath = useLocation().pathname
1218
const { isBelowLarge } = useScreenWidth()
1319

14-
const [sidebarVisible, setSidebarVisible] = useState(false)
20+
const sidebarVisible = useStore(sidebarVisibleState)
1521

1622
useEffect(() => {
1723
if (!isBelowLarge) {

src/components/Content/ContentContext.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ export const ContextProvider = ({ children }) => {
7171
}
7272
}, ANIMATION_DURATION_MS)
7373
},
74-
[polyglot, handleEntryStatusUpdate, markReadBy, location.pathname],
74+
[polyglot, handleEntryStatusUpdate, markReadBy, location.pathname, navigate],
7575
)
7676

7777
const value = useMemo(

src/components/Settings/FeedList.jsx

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import {
1414
import { IconDelete, IconEdit, IconQuestionCircle, IconRefresh } from "@arco-design/web-react/icon"
1515
import { useStore } from "@nanostores/react"
1616
import { atom, computed } from "nanostores"
17-
import { Fragment, useEffect, useState } from "react"
17+
import { Fragment, useEffect, useMemo, useState } from "react"
1818
import { useNavigate } from "react-router"
1919

2020
import { refreshAllFeed, updateFeed } from "@/apis"
@@ -359,6 +359,7 @@ const FeedList = () => {
359359

360360
const [bulkUpdateModalVisible, setBulkUpdateModalVisible] = useState(false)
361361
const [bulkOperationsModalVisible, setBulkOperationsModalVisible] = useState(false)
362+
const [currentPage, setCurrentPage] = useState(1)
362363
const [refreshModalVisible, setRefreshModalVisible] = useState(false)
363364
const [editFeedModalVisible, setEditFeedModalVisible] = useState(false)
364365
const [feedForm] = Form.useForm()
@@ -506,28 +507,21 @@ const FeedList = () => {
506507
},
507508
].filter(Boolean)
508509

509-
const [pagination, setPagination] = useState({
510-
showJumper: true,
511-
showTotal: true,
512-
total: tableData.length,
513-
pageSize: 15,
514-
current: 1,
515-
sizeCanChange: false,
516-
})
517-
518-
const handleTableChange = (pagination) => {
519-
setPagination((prev) => ({
520-
...prev,
521-
current: pagination.current,
522-
}))
523-
}
524-
525-
useEffect(() => {
526-
setPagination((prev) => ({
527-
...prev,
510+
const pagination = useMemo(
511+
() => ({
512+
showJumper: true,
513+
showTotal: true,
528514
total: tableData.length,
529-
}))
530-
}, [tableData.length])
515+
pageSize: 15,
516+
current: currentPage,
517+
sizeCanChange: false,
518+
}),
519+
[tableData.length, currentPage],
520+
)
521+
522+
const handleTableChange = (newPagination) => {
523+
setCurrentPage(newPagination.current)
524+
}
531525

532526
return (
533527
<>

src/components/Sidebar/Sidebar.jsx

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ import {
3030
} from "@arco-design/web-react/icon"
3131
import { useStore } from "@nanostores/react"
3232
import classNames from "classnames"
33-
import { useEffect, useMemo, useRef, useState } from "react"
33+
import { useMemo, useRef, useState } from "react"
3434
import { useLocation, useNavigate } from "react-router"
3535
import SimpleBar from "simplebar-react"
3636
import { Virtualizer } from "virtua"
@@ -580,12 +580,10 @@ const updateAllEntriesAsRead = () => {
580580
}
581581

582582
const Sidebar = () => {
583-
const { homePage } = useStore(settingsState)
584583
const { isCoreDataReady } = useStore(dataState)
585584
const { polyglot } = useStore(polyglotState)
586585
const expandedCategories = useStore(expandedCategoriesState)
587586

588-
const [selectedKeys, setSelectedKeys] = useState([`/${homePage}`])
589587
const [categoryModalVisible, setCategoryModalVisible] = useState(false)
590588
const [feedModalVisible, setFeedModalVisible] = useState(false)
591589
const [selectedCategory, setSelectedCategory] = useState(null)
@@ -598,14 +596,11 @@ const Sidebar = () => {
598596

599597
const location = useLocation()
600598
const currentPath = location.pathname
599+
const selectedKeys = useMemo(() => [currentPath], [currentPath])
601600

602601
const { fetchCounters } = useAppData()
603602
const { infoFrom, infoId } = useStore(contentState)
604603

605-
useEffect(() => {
606-
setSelectedKeys([currentPath])
607-
}, [currentPath])
608-
609604
const handleEditCategory = (category) => {
610605
setSelectedCategory(category)
611606
setCategoryModalVisible(true)

src/components/ui/FeedIcon.jsx

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useEffect, useRef, useState } from "react"
1+
import { useRef, useState } from "react"
22

33
import useFeedIcons from "@/hooks/useFeedIcons"
44
import { updateFeedIcon } from "@/store/feedIconsState"
@@ -15,43 +15,47 @@ const FeedIcon = ({ feed, className = "feed-icon" }) => {
1515
const { icon_id: iconId } = feed.icon
1616
const fallbackIconURL = getFallbackIconURL(feed)
1717

18-
const [iconURL, setIconURL] = useState(iconId === 0 ? fallbackIconURL : DEFAULT_ICON_URL)
18+
const [useFallback, setUseFallback] = useState(false)
1919
const [fallbackFailed, setFallbackFailed] = useState(false)
2020

2121
const imgRef = useRef(null)
2222

2323
const fetchedIcon = useFeedIcons(iconId, feed)
2424
const fetchedIconURL = fetchedIcon?.url
2525

26-
useEffect(() => {
27-
if (fetchedIconURL) {
28-
setIconURL(fetchedIconURL)
29-
} else if (iconId === 0 && !fallbackFailed) {
30-
setIconURL(fallbackIconURL)
26+
const iconURL = (() => {
27+
if (fallbackFailed) {
28+
return DEFAULT_ICON_URL
3129
}
32-
}, [fetchedIconURL, iconId, fallbackFailed, fallbackIconURL])
30+
if (fetchedIconURL && !useFallback) {
31+
return fetchedIconURL
32+
}
33+
if (iconId === 0 || useFallback) {
34+
return fallbackIconURL
35+
}
36+
return DEFAULT_ICON_URL
37+
})()
3338

3439
const handleImageLoad = () => {
3540
if (imgRef.current) {
3641
const { naturalWidth, naturalHeight } = imgRef.current
3742
if (naturalWidth > 200 && naturalHeight > 200 && fetchedIcon.width === null) {
3843
updateFeedIcon(iconId, { width: naturalWidth, height: naturalHeight })
3944
}
40-
if ((naturalWidth !== naturalHeight || naturalWidth === 0) && !fallbackFailed) {
41-
setIconURL(fallbackIconURL)
45+
if ((naturalWidth !== naturalHeight || naturalWidth === 0) && !useFallback) {
46+
setUseFallback(true)
4247
}
4348
}
4449
}
4550

4651
const handleError = () => {
4752
if (iconURL === fallbackIconURL && !fallbackFailed) {
4853
setFallbackFailed(true)
49-
setIconURL(DEFAULT_ICON_URL)
5054
return
5155
}
5256

53-
if (!fallbackFailed) {
54-
setIconURL(fallbackIconURL)
57+
if (!fallbackFailed && !useFallback) {
58+
setUseFallback(true)
5559
}
5660
}
5761

src/hooks/useKeyHandlers.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import {
1212
filteredEntriesState,
1313
nextContentState,
1414
prevContentState,
15-
setActiveContent,
1615
} from "@/store/contentState"
1716
import { ANIMATION_DURATION_MS } from "@/utils/constants"
1817
import { extractImageSources } from "@/utils/images"
@@ -69,6 +68,7 @@ const useKeyHandlers = () => {
6968
}
7069

7170
const exitDetailView = withActiveContent(
71+
// eslint-disable-next-line react-hooks/refs
7272
withPhotoSliderCheck(() => {
7373
closeActiveContent()
7474
if (entryListRef.current) {
@@ -77,6 +77,7 @@ const useKeyHandlers = () => {
7777
}),
7878
)
7979

80+
// eslint-disable-next-line react-hooks/refs
8081
const navigateToPreviousArticle = withPhotoSliderCheck(() => {
8182
if (prevContent) {
8283
handleEntryClick(prevContent)
@@ -86,6 +87,7 @@ const useKeyHandlers = () => {
8687
}
8788
})
8889

90+
// eslint-disable-next-line react-hooks/refs
8991
const navigateToNextArticle = withPhotoSliderCheck(() => {
9092
if (nextContent) {
9193
handleEntryClick(nextContent)
@@ -95,6 +97,7 @@ const useKeyHandlers = () => {
9597
}
9698
})
9799

100+
// eslint-disable-next-line react-hooks/refs
98101
const navigateToAdjacentUnreadArticle = withPhotoSliderCheck((direction) => {
99102
const adjacentUnreadEntry = findAdjacentUnreadEntry(
100103
activeEntryIndex,

src/pages/Login.jsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ import useForm from "@arco-design/web-react/es/Form/useForm"
1212
import { IconHome, IconLock, IconUser } from "@arco-design/web-react/icon"
1313
import { useStore } from "@nanostores/react"
1414
import { ofetch } from "ofetch"
15-
import { useEffect, useState } from "react"
16-
import { Navigate, useLocation, useNavigate } from "react-router"
15+
import { useEffect, useMemo, useState } from "react"
16+
import { Navigate, useLocation, useNavigate, useSearchParams } from "react-router"
1717

1818
import useLanguage, { polyglotState } from "@/hooks/useLanguage"
1919
import useTheme from "@/hooks/useTheme"
@@ -34,7 +34,10 @@ const Login = () => {
3434

3535
const [loginForm] = useForm()
3636
const [loading, setLoading] = useState(false)
37-
const [authMethod, setAuthMethod] = useState("token")
37+
38+
const [searchParams] = useSearchParams()
39+
const urlParamsObj = useMemo(() => Object.fromEntries(searchParams), [])
40+
const [authMethod, setAuthMethod] = useState(urlParamsObj.username ? "user" : "token")
3841
/* token or user */
3942
const location = useLocation()
4043
const navigate = useNavigate()
@@ -83,9 +86,6 @@ const Login = () => {
8386
const url = new URL(globalThis.location.href)
8487
const { server, token, username, password } = Object.fromEntries(url.searchParams)
8588
if (server) {
86-
if (username) {
87-
setAuthMethod("user")
88-
}
8989
loginForm.setFieldsValue({ server, token, username, password })
9090
loginForm.submit()
9191
}

0 commit comments

Comments
 (0)