Skip to content

Commit 7caaa64

Browse files
authored
Merge pull request #213 from atomic-state/fixes/unexpected-revalidation
fixes(mutate):
2 parents 82405a8 + 033e6c6 commit 7caaa64

File tree

3 files changed

+61
-86
lines changed

3 files changed

+61
-86
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "http-react",
3-
"version": "3.8.2",
3+
"version": "3.8.3",
44
"description": "React hooks for data fetching",
55
"main": "dist/index.js",
66
"scripts": {

src/hooks/use-fetch.ts

Lines changed: 53 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ import {
5555
createImperativeFetch,
5656
getMiliseconds,
5757
getTimePassed,
58+
mutateData,
5859
revalidate,
5960
useIsomorphicLayoutEffect
6061
} from '../utils'
@@ -1040,98 +1041,53 @@ export function useFetch<FetchDataType = any, TransformData = any>(
10401041
]
10411042
)
10421043

1043-
// At the top of your component, create a ref to hold all dependencies for the listener.
1044-
const listenerDeps = useRef({
1045-
thisDeps,
1046-
idString,
1047-
requestCallId,
1048-
forceMutate,
1049-
imperativeFetch,
1050-
setData,
1051-
setOnline,
1052-
setLoading,
1053-
setError,
1054-
setCompletedAttempts,
1055-
handleMutate,
1056-
url,
1057-
onMutate
1058-
})
1059-
1060-
// On every render, update the ref's current value to ensure the listener always has the latest functions and props.
1061-
// This does not trigger the effect below.
1062-
listenerDeps.current = {
1063-
thisDeps,
1064-
idString,
1065-
requestCallId,
1066-
forceMutate,
1067-
imperativeFetch,
1068-
setData,
1069-
setOnline,
1070-
setLoading,
1071-
setError,
1072-
setCompletedAttempts,
1073-
handleMutate,
1074-
url,
1075-
onMutate
1076-
}
1077-
10781044
useEffect(() => {
1079-
function waitFormUpdates(event: any) {
1080-
// Destructure the latest dependencies from the ref inside the listener
1081-
const deps = listenerDeps.current
1045+
function waitFormUpdates(v: any) {
10821046
const {
10831047
isMutating,
10841048
data: $data,
10851049
error: $error,
10861050
online,
10871051
loading,
10881052
completedAttempts
1089-
} = event || {}
1053+
} = v || {}
10901054

1091-
// 1. Handle mutations with cleaner logic
1092-
if (
1093-
isMutating &&
1094-
serialize($data) !== serialize(cacheForMutation.get(resolvedKey))
1095-
) {
1096-
cacheForMutation.set(deps.idString, $data)
1097-
deps.forceMutate($data)
1098-
1099-
if (deps.handleMutate) {
1100-
const canCallOnMutate =
1101-
deps.url === '' || !runningMutate.get(resolvedKey)
1102-
if (canCallOnMutate) {
1103-
if (deps.url !== '') runningMutate.set(resolvedKey, true)
1104-
;(deps.onMutate as any)($data, deps.imperativeFetch)
1105-
}
1106-
}
1107-
}
1055+
if (isMutating) {
1056+
if (!jsonCompare($data, cacheForMutation.get(resolvedKey))) {
1057+
cacheForMutation.set(idString, $data)
11081058

1109-
// 2. Handle state synchronization from other hooks
1110-
if (
1111-
event.requestCallId !== deps.requestCallId &&
1112-
!willSuspend.get(resolvedKey)
1113-
) {
1114-
// Create a map to avoid the long if-chain
1115-
const stateUpdates = {
1116-
data: { value: $data, setter: deps.setData },
1117-
online: { value: online, setter: deps.setOnline },
1118-
loading: { value: loading, setter: deps.setLoading },
1119-
error: { value: $error, setter: deps.setError },
1120-
completedAttempts: {
1121-
value: completedAttempts,
1122-
setter: deps.setCompletedAttempts
1059+
if (isMutating) {
1060+
if (handleMutate) {
1061+
if (url === '') {
1062+
;(onMutate as any)($data, imperativeFetch)
1063+
} else {
1064+
if (!runningMutate.get(resolvedKey)) {
1065+
runningMutate.set(resolvedKey, true)
1066+
;(onMutate as any)($data, imperativeFetch)
1067+
}
1068+
}
1069+
}
11231070
}
11241071
}
1072+
}
11251073

1126-
// Loop through the map to update state concisely using a transition
1127-
startTransition(() => {
1128-
for (const key in stateUpdates) {
1129-
const update = stateUpdates[key as keyof typeof stateUpdates]
1130-
if (
1131-
deps.thisDeps[key as keyof typeof stateUpdates] &&
1132-
isDefined(update.value)
1133-
) {
1134-
update.setter(update.value)
1074+
if (v.requestCallId !== requestCallId) {
1075+
queue(() => {
1076+
if (!willSuspend.get(resolvedKey)) {
1077+
if (inDeps('data') && isDefined($data)) {
1078+
setData($data)
1079+
}
1080+
if (inDeps('online') && isDefined(online)) {
1081+
setOnline(online)
1082+
}
1083+
if (inDeps('loading') && isDefined(loading)) {
1084+
setLoading(loading)
1085+
}
1086+
if (inDeps('error') && isDefined($error)) {
1087+
setError($error)
1088+
}
1089+
if (inDeps('completedAttempts') && isDefined(completedAttempts)) {
1090+
setCompletedAttempts(completedAttempts)
11351091
}
11361092
}
11371093
})
@@ -1143,7 +1099,22 @@ export function useFetch<FetchDataType = any, TransformData = any>(
11431099
return () => {
11441100
requestsProvider.removeListener(resolvedKey, waitFormUpdates)
11451101
}
1146-
}, [resolvedKey])
1102+
}, [
1103+
// thisDeps,
1104+
resolvedKey,
1105+
idString,
1106+
requestCallId,
1107+
forceMutate,
1108+
imperativeFetch,
1109+
setData,
1110+
setOnline,
1111+
setLoading,
1112+
setError,
1113+
setCompletedAttempts,
1114+
handleMutate,
1115+
url,
1116+
onMutate
1117+
])
11471118

11481119
const reValidate = useCallback(
11491120
async function reValidate() {
@@ -1307,6 +1278,7 @@ export function useFetch<FetchDataType = any, TransformData = any>(
13071278

13081279
useEffect(() => {
13091280
// Attempts will be made after a request fails
1281+
13101282
const tm = setTimeout(() => {
13111283
if (!gettingAttempts.get(resolvedKey)) {
13121284
gettingAttempts.set(resolvedKey, true)
@@ -1727,6 +1699,7 @@ Learn more: https://httpr.vercel.app/docs/api#suspense
17271699
submit,
17281700
get mutate() {
17291701
thisDeps.data = true
1702+
17301703
return forceMutate
17311704
},
17321705
get fetcher() {

src/utils/shared.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -68,12 +68,14 @@ function canHaveBody(method: keyof typeof METHODS) {
6868
}
6969

7070
export function queue(callback: any, time: number = 0) {
71-
const tm = setTimeout(() => {
72-
callback();
73-
clearTimeout(tm);
74-
}, time);
71+
queueMicrotask(callback);
7572

76-
return tm;
73+
// const tm = setTimeout(() => {
74+
// callback();
75+
// clearTimeout(tm);
76+
// }, time);
77+
78+
// return tm;
7779
}
7880

7981
/**

0 commit comments

Comments
 (0)