Skip to content

Commit 87cf235

Browse files
vtgrachevViktor Grachev
andauthored
fix: check "if (!error)" skip error if value is cast to false (#4118)
Co-authored-by: Viktor Grachev <[email protected]>
1 parent ba10cf9 commit 87cf235

File tree

2 files changed

+35
-4
lines changed

2 files changed

+35
-4
lines changed

src/_internal/utils/mutate.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ export async function internalMutate<Data>(
123123

124124
let data: any = _data
125125
let error: unknown
126+
let isError = false
126127

127128
// Update global timestamps.
128129
const beforeMutationTs = getTimestamp()
@@ -155,6 +156,7 @@ export async function internalMutate<Data>(
155156
} catch (err) {
156157
// If it throws an error synchronously, we shouldn't update the cache.
157158
error = err
159+
isError = true
158160
}
159161
}
160162

@@ -164,15 +166,16 @@ export async function internalMutate<Data>(
164166
// avoid race conditions.
165167
data = await (data as Promise<Data>).catch(err => {
166168
error = err
169+
isError = true
167170
})
168171

169172
// Check if other mutations have occurred since we've started this mutation.
170173
// If there's a race we don't update cache or broadcast the change,
171174
// just return the data.
172175
if (beforeMutationTs !== MUTATION[key][0]) {
173-
if (error) throw error
176+
if (isError) throw error
174177
return data
175-
} else if (error && hasOptimisticData && rollbackOnError(error)) {
178+
} else if (isError && hasOptimisticData && rollbackOnError(error)) {
176179
// Rollback. Always populate the cache in this case but without
177180
// transforming the data.
178181
populateCache = true
@@ -184,7 +187,7 @@ export async function internalMutate<Data>(
184187

185188
// If we should write back the cache after request.
186189
if (populateCache) {
187-
if (!error) {
190+
if (!isError) {
188191
// Transform the result into data.
189192
if (isFunction(populateCache)) {
190193
const populateCachedData = populateCache(data, committedData)
@@ -207,7 +210,7 @@ export async function internalMutate<Data>(
207210
})
208211

209212
// Throw error or return data
210-
if (error) {
213+
if (isError) {
211214
if (throwOnError) throw error
212215
return
213216
}

test/use-swr-remote-mutation.test.tsx

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1112,4 +1112,32 @@ describe('useSWR - remote mutation', () => {
11121112

11131113
expect(error.message).toBe('Can’t trigger the mutation: missing key.')
11141114
})
1115+
1116+
it('should call `onError` and `onRejected` but do not call `onSuccess` if value an error is cast to false', async () => {
1117+
const key = createKey()
1118+
const onSuccess = jest.fn()
1119+
const onError = jest.fn()
1120+
const onRejected = jest.fn()
1121+
1122+
const fetcher = () => {
1123+
return new Promise((_, reject) => reject(''));
1124+
};
1125+
1126+
function Page() {
1127+
const { trigger } = useSWRMutation(key, fetcher, { onError, onSuccess })
1128+
1129+
return <button onClick={() => trigger().catch(onRejected)}>trigger</button>
1130+
}
1131+
1132+
render(<Page />)
1133+
1134+
await screen.findByText('trigger')
1135+
fireEvent.click(screen.getByText('trigger'))
1136+
1137+
await nextTick()
1138+
1139+
expect(onSuccess).not.toHaveBeenCalled()
1140+
expect(onError).toHaveBeenCalled()
1141+
expect(onRejected).toHaveBeenCalled()
1142+
})
11151143
})

0 commit comments

Comments
 (0)