Skip to content

Commit

Permalink
fix(query-core): handle errors that occur inside setData method (#7966
Browse files Browse the repository at this point in the history
)

* fix(query-core): add test case for not serializable data

* fix(query-core): handle `setData` error

* Update packages/query-core/src/__tests__/query.test.tsx

* fix(query-core): add `return` statement

* fix(query-core): throw the error in case when data is not serializable for non production env

* fix(query-core): delete packages/query-core/tsconfig.vitest-temp.json

* fix(query-core): lift serializability check and add console.error

* chore: message

---------

Co-authored-by: Dominik Dorfmeister <office@dorfmeister.cc>
  • Loading branch information
Efimenko and TkDodo committed Aug 30, 2024
1 parent 82bfc34 commit 50315ac
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 1 deletion.
49 changes: 49 additions & 0 deletions packages/query-core/src/__tests__/query.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -965,4 +965,53 @@ describe('query', () => {
await sleep(60) // let it resolve
expect(spy).toHaveBeenCalledWith('1 - 2')
})

it('should have an error status when queryFn data is not serializable', async () => {
const consoleMock = vi.spyOn(console, 'error')

consoleMock.mockImplementation(() => undefined)

const key = queryKey()

const queryFn = vi.fn()

queryFn.mockImplementation(async () => {
await sleep(10)

const data: Array<{
id: number
name: string
link: null | { id: number; name: string; link: unknown }
}> = Array.from({ length: 5 })
.fill(null)
.map((_, index) => ({
id: index,
name: `name-${index}`,
link: null,
}))

if (data[0] && data[1]) {
data[0].link = data[1]
data[1].link = data[0]
}

return data
})

await queryClient.prefetchQuery({ queryKey: key, queryFn })

const query = queryCache.find({ queryKey: key })!

expect(queryFn).toHaveBeenCalledTimes(1)

expect(consoleMock).toHaveBeenCalledWith(
expect.stringContaining(
'StructuralSharing requires data to be JSON serializable',
),
)

expect(query.state.status).toBe('error')

consoleMock.mockRestore()
})
})
7 changes: 6 additions & 1 deletion packages/query-core/src/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -499,7 +499,12 @@ export class Query<
return
}

this.setData(data)
try {
this.setData(data)
} catch (error) {
onError(error as TError)
return
}

// Notify cache callback
this.#cache.config.onSuccess?.(data, this as Query<any, any, any, any>)
Expand Down
13 changes: 13 additions & 0 deletions packages/query-core/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,19 @@ export function replaceData<
if (typeof options.structuralSharing === 'function') {
return options.structuralSharing(prevData, data) as TData
} else if (options.structuralSharing !== false) {
if (process.env.NODE_ENV !== 'production') {
try {
JSON.stringify(prevData)
JSON.stringify(data)
} catch (error) {
console.error(
`StructuralSharing requires data to be JSON serializable. To fix this, turn off structuralSharing or return JSON-serializable data from your queryFn. [${options.queryHash}]: ${error}`,
)

throw new Error('Data is not serializable')
}
}

// Structurally share data between prev and new data if needed
return replaceEqualDeep(prevData, data)
}
Expand Down

0 comments on commit 50315ac

Please sign in to comment.