Skip to content

Commit e0bf884

Browse files
refactor for new react state handle pattern with useEffect. removed unnecessary useEffects
1 parent be50cd6 commit e0bf884

12 files changed

Lines changed: 104 additions & 80 deletions

File tree

src/renderer/src/components/app/collections/request/request/api-url/ApiUrl.tsx

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,4 @@
1-
import {
2-
type FormEvent,
3-
memo,
4-
useCallback,
5-
useEffect,
6-
useRef,
7-
useState,
8-
} from "react";
1+
import { type FormEvent, memo, useCallback, useEffect, useState } from "react";
92
import ApiMethodSelector from "@/components/app/collections/request/request/api-url/ApiMethodSelector";
103
import ApiInput from "@/components/app/collections/request/request/api-url/ApiInput";
114
import ApiCta from "@/components/app/collections/request/request/api-url/ApiCta";
@@ -22,14 +15,14 @@ import { fetchApi } from "@/context/redux/request-response/thunks/rest-api";
2215
const ApiUrl = memo(() => {
2316
const dispatch = useAppDispatch();
2417
const apiUrl = useAppSelector(selectRequestUrl);
25-
const apiUrlRef = useRef<string>(apiUrl);
2618
const [url, setUrl] = useState<string>(apiUrl);
27-
const [isError, setIsError] = useState<boolean>(false);
19+
const [prevApiUrl, setPrevApiUrl] = useState<string>(apiUrl);
20+
const isError = !isStrictApiUrl(url);
2821

29-
useEffect(() => {
22+
if (apiUrl !== prevApiUrl) {
3023
setUrl(apiUrl);
31-
apiUrlRef.current = apiUrl;
32-
}, [apiUrl]);
24+
setPrevApiUrl(apiUrl);
25+
}
3326

3427
useEffect(() => {
3528
const handleKeyDown = (e: KeyboardEvent) => {
@@ -40,8 +33,7 @@ const ApiUrl = memo(() => {
4033
}, [dispatch]);
4134

4235
useEffect(() => {
43-
setIsError(!isStrictApiUrl(url));
44-
if (url === apiUrlRef.current) return;
36+
if (url === apiUrl) return;
4537
const timeout = setTimeout(() => {
4638
dispatch(
4739
changeRequestApiUrl({
@@ -50,7 +42,7 @@ const ApiUrl = memo(() => {
5042
);
5143
}, 500);
5244
return () => clearTimeout(timeout);
53-
}, [dispatch, url]);
45+
}, [apiUrl, dispatch, url]);
5446

5547
const handleApiUrlChange = (value: string) => setUrl(value);
5648

src/renderer/src/components/app/collections/request/response/meta-data/ResponseMetaWrapper.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ const ResponseMetaWrapper = ({ children, className, ...props }: Props) => {
1010
return (
1111
<section
1212
className={cn(
13-
"flex justify-between items-center gap-2 px-2.5 min-h-10 border-b-2 border-border/5",
13+
"flex justify-between items-center gap-2 px-2.5 min-h-10 border-b-2 border-border/50",
1414
className,
1515
)}
1616
{...props}

src/renderer/src/components/app/setting/content/http-status/SettingHttpList.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ const SettingHttpList = memo(() => {
3535
const statusList = useAppSelector(selectHttpStatusList);
3636

3737
const list = useMemo(() => {
38-
const categorizedList = statusSectionListObj;
38+
const categorizedList = structuredClone(statusSectionListObj);
3939
Object.keys(statusList).forEach(code => {
4040
const index = Number(code[0]) - 1;
4141
categorizedList[index].value[code] = {

src/renderer/src/components/ui/paste-button.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ const PasteButton = memo(
5757
};
5858

5959
useEffect(() => {
60+
// eslint-disable-next-line react-hooks/set-state-in-effect
6061
checkClipboard();
6162

6263
window.addEventListener("focus", checkClipboard);

src/renderer/src/context/collections/CollectionProvider.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { DEFAULT_AUTHORIZATION_ID } from "@/constant/authorization.constant";
1010
import { loadInheritParentAuthorization } from "@/context/redux/request-response/thunks/auth";
1111
import type { TAuthContextType } from "@shared/types/authorization.types";
1212
import { selectSelectedTab } from "@/context/redux/request-response/selectors/tab-list";
13+
import { selectIsLoadingInheritParentAuthorization } from "@/context/redux/status/selectors/authorization";
1314

1415
interface CollectionContext {
1516
isLoading: boolean;
@@ -34,16 +35,14 @@ interface CollectionProviderProps {
3435

3536
const CollectionProvider = ({ children, type }: CollectionProviderProps) => {
3637
const dispatch = useAppDispatch();
37-
const [isLoading, setIsLoading] = useState<boolean>(true);
38+
const isLoading = useAppSelector(selectIsLoadingInheritParentAuthorization);
3839
const selectedTab = useAppSelector(selectSelectedTab);
3940
const id = type === "global" ? DEFAULT_AUTHORIZATION_ID : selectedTab;
4041

4142
const handleLoadInheritParentAuthorization = useCallback(
4243
async (id?: string | null) => {
4344
if (!id) return;
44-
setIsLoading(true);
4545
await dispatch(loadInheritParentAuthorization(id));
46-
setIsLoading(false);
4746
},
4847
[dispatch],
4948
);

src/renderer/src/context/environments/EnvironmentsProvider.tsx

Lines changed: 25 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import React, {
33
useCallback,
44
useContext,
55
useEffect,
6+
useMemo,
67
useRef,
78
useState,
89
} from "react";
@@ -56,51 +57,44 @@ const EnvironmentsProvider = ({ children }: EnvironmentsProviderProps) => {
5657
const environmentsListFromStore = useAppSelector(
5758
state => state.environments.environmentsList ?? {},
5859
);
59-
60-
const [environmentsListState, setEnvironmentsListState] = useState<
61-
Record<string, EnvironmentInterface>
62-
>({});
63-
const [searchQuery, setSearchQuery] = useState("");
64-
65-
/* Update the list whenever the main list or search query changes */
66-
const updateFilteredEnvironments = useCallback(
67-
(query: string) => {
68-
setEnvironmentsListState(
69-
searchFilteredEnvironments({
70-
searchQuery: query,
71-
environmentsList: environmentsListFromStore,
72-
}),
73-
);
74-
},
75-
[environmentsListFromStore],
60+
const [searchQuery, setSearchQuery] = useState<string>("");
61+
const [debouncedQuery, setDebouncedQuery] = useState<string>("");
62+
63+
const environmentsListState = useMemo(
64+
() =>
65+
searchFilteredEnvironments({
66+
searchQuery: debouncedQuery,
67+
environmentsList: environmentsListFromStore,
68+
}),
69+
[debouncedQuery, environmentsListFromStore],
7670
);
7771

7872
/* Debounced search */
79-
const handleSearch = useCallback(
80-
(value: string) => {
81-
if (debounceTimeout.current) clearTimeout(debounceTimeout.current);
73+
const handleSearch = useCallback((value: string) => {
74+
if (debounceTimeout.current) clearTimeout(debounceTimeout.current);
8275

83-
debounceTimeout.current = setTimeout(() => {
84-
updateFilteredEnvironments(value);
85-
}, DEBOUNCE_DELAY);
86-
},
87-
[updateFilteredEnvironments],
88-
);
76+
debounceTimeout.current = setTimeout(
77+
() => setDebouncedQuery(value),
78+
DEBOUNCE_DELAY,
79+
);
80+
}, []);
8981

9082
/* Handle input change */
9183
const handleChangeSearchQuery = useCallback(
9284
(value: string) => {
9385
setSearchQuery(value);
86+
87+
if (!value) {
88+
if (debounceTimeout.current) clearTimeout(debounceTimeout.current);
89+
setDebouncedQuery("");
90+
return;
91+
}
92+
9493
handleSearch(value);
9594
},
9695
[handleSearch],
9796
);
9897

99-
/* Initialize environments list on mount and whenever the store updates */
100-
useEffect(() => {
101-
updateFilteredEnvironments(searchQuery);
102-
}, [environmentsListFromStore, searchQuery, updateFilteredEnvironments]);
103-
10498
/* Clean up debounce on unmount */
10599
useEffect(() => {
106100
return () => {

src/renderer/src/context/history/HistoryDetailsProvider.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ const HistoryDetailsProvider = ({ children }: HistoryDetailsProviderProps) => {
5858
selectHistoryReplacingIsLoading,
5959
);
6060
const isLoading = isHistoryDetailsLoading || isHistoryReplacinglsLoading;
61+
const [prevHistoryId, setPrevHistoryId] = useState<string | null>(historyId);
6162
const [activeMetaTab, setActiveMetaTab] = useState<TActiveTabType>("params");
6263
const [codeWrap, setCodeWrap] = useState<boolean>(false);
6364
const [isReplaceAlertOpen, setIsReplaceAlertOpen] = useState<boolean>(false);
@@ -80,9 +81,10 @@ const HistoryDetailsProvider = ({ children }: HistoryDetailsProviderProps) => {
8081
dispatch(loadRequestHistory());
8182
}, [dispatch, isOpen]);
8283

83-
useEffect(() => {
84+
if (prevHistoryId !== historyId) {
8485
setActiveMetaTab("params");
85-
}, [historyId]);
86+
setPrevHistoryId(historyId);
87+
}
8688

8789
return (
8890
<HistoryDetailsContext.Provider

src/renderer/src/context/keyboard-shortcuts/KeyboardShortcutsProvider.tsx

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ const KeyboardShortcutsProvider = ({
8686
children,
8787
}: KeyboardShortcutsProviderProps) => {
8888
const projectId = useAppSelector(selectActiveProjectId);
89+
const [prevProjectId, setPrevProjectId] = useState<string | null>(projectId);
8990
const [activeTab, setActiveTab] = useState<TKeyboardShortcutsTab>(
9091
projectId ? "local" : "global",
9192
);
@@ -97,9 +98,6 @@ const KeyboardShortcutsProvider = ({
9798
useState<SearchKeyListInterface>(searchKeyListInitial);
9899
const [selectedSearchByType, setSelectedSearchByType] =
99100
useState<SelectedSearchByTypeInterface>(selectedSearchByTypeInitial);
100-
const [searchResult, setSearchResult] = useState<
101-
Record<string, KeybaordShortCutInterface>
102-
>({});
103101

104102
const applyingKeybindingMap = useMemo(() => {
105103
if (activeTab === "global") return globalMap;
@@ -110,7 +108,7 @@ const KeyboardShortcutsProvider = ({
110108
};
111109
}, [activeTab, globalMap, localMap]);
112110

113-
useEffect(() => {
111+
const searchResult = useMemo(() => {
114112
const keybindingMap: Record<string, KeybaordShortCutInterface> = {};
115113

116114
/* if search term or search keys are emtpy then render whole list */
@@ -120,7 +118,7 @@ const KeyboardShortcutsProvider = ({
120118
(selectedSearchByType[activeTab] === "keyboard" &&
121119
!searchKeyList[activeTab].length)
122120
)
123-
return setSearchResult(applyingKeybindingMap);
121+
return applyingKeybindingMap;
124122

125123
Object.entries(applyingKeybindingMap).map(([id, data]) => {
126124
const isSearchTermMatched =
@@ -142,8 +140,7 @@ const KeyboardShortcutsProvider = ({
142140
};
143141
}
144142
});
145-
146-
setSearchResult(keybindingMap);
143+
return keybindingMap;
147144
}, [
148145
activeTab,
149146
applyingKeybindingMap,
@@ -152,11 +149,27 @@ const KeyboardShortcutsProvider = ({
152149
selectedSearchByType,
153150
]);
154151

155-
useEffect(() => setActiveTab(projectId ? "local" : "global"), [projectId]);
152+
useEffect(() => {}, [
153+
activeTab,
154+
applyingKeybindingMap,
155+
searchKeyList,
156+
searchTerm,
157+
selectedSearchByType,
158+
]);
159+
160+
if (
161+
prevProjectId !== projectId &&
162+
(projectId ? "local" : "global") !== activeTab
163+
) {
164+
setActiveTab(projectId ? "local" : "global");
165+
setPrevProjectId(projectId);
166+
}
156167

157-
const handleChangeActiveTab = useCallback((value?: TKeyboardShortcutsTab) => {
158-
setActiveTab(prev => value ?? (prev === "global" ? "local" : "global"));
159-
}, []);
168+
const handleChangeActiveTab = useCallback(
169+
(value?: TKeyboardShortcutsTab) =>
170+
setActiveTab(prev => value ?? (prev === "global" ? "local" : "global")),
171+
[],
172+
);
160173

161174
const handleChangeSearchTerm = useCallback(
162175
(value?: string) => {

src/renderer/src/context/local-password/LocalPasswordProvider.tsx

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,4 @@
1-
import React, {
2-
createContext,
3-
useContext,
4-
useEffect,
5-
useRef,
6-
useState,
7-
} from "react";
1+
import React, { createContext, useContext, useState } from "react";
82
import { useAppSelector } from "@/context/redux/hooks";
93
import { selectHaveLocalPassword } from "@/context/redux/local-password/selectors/local-password";
104
import { selectLocalPasswordIsLoading } from "@/context/redux/status/selectors/local-password";
@@ -39,20 +33,19 @@ interface LocalPasswordProviderProps {
3933
const LocalPasswordProvider = ({ children }: LocalPasswordProviderProps) => {
4034
const haveLocalPassword = useAppSelector(selectHaveLocalPassword);
4135
const isLocalPasswordLoading = useAppSelector(selectLocalPasswordIsLoading);
42-
const [stage, setStage] = useState<TLocalPasswordStage | null>(null);
36+
const [stage, setStage] = useState<TLocalPasswordStage | null>(() => {
37+
if (isLocalPasswordLoading) return null;
38+
return haveLocalPassword ? "protect" : "change";
39+
});
4340
const [isDisableRequest, setIsDisableRequest] = useState<boolean>(false);
44-
const initialized = useRef<boolean>(false);
4541

4642
const handleChangeStage = (level: TLocalPasswordStage) => setStage(level);
4743

4844
const handleChangeDisableRequest = (value: boolean) =>
4945
setIsDisableRequest(value);
5046

51-
useEffect(() => {
52-
if (isLocalPasswordLoading || initialized.current) return;
47+
if (stage === null && !isLocalPasswordLoading)
5348
setStage(haveLocalPassword ? "protect" : "change");
54-
initialized.current = true;
55-
}, [haveLocalPassword, isLocalPasswordLoading]);
5649

5750
return (
5851
<LocalPasswordContext.Provider
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { createSelector } from "@reduxjs/toolkit";
2+
import type { RootState } from "@/context/redux/store";
3+
4+
export const selectIsLoadingInheritParentAuthorization = createSelector(
5+
[(state: RootState) => state.status.isLoadingInheritParentAuthorization],
6+
isLoading => isLoading,
7+
);

0 commit comments

Comments
 (0)