Skip to content

Commit 213d243

Browse files
committed
refetch after paint and not in render
1 parent f46fad8 commit 213d243

13 files changed

Lines changed: 227 additions & 37 deletions

app/src/resources/camera/useNotifyCamera.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { useEffect } from 'react'
2+
13
import { useCamera } from '@opentrons/react-api-client'
24

35
import { useNotifyDataReady } from '../useNotifyDataReady'
@@ -16,9 +18,14 @@ export function useNotifyCamera(
1618

1719
const httpQueryResult = useCamera(queryOptionsNotify)
1820

19-
if (shouldRefetch) {
20-
void httpQueryResult.refetch()
21-
}
21+
useEffect(() => {
22+
if (shouldRefetch) {
23+
void httpQueryResult.refetch()
24+
}
25+
26+
// refetch is stable, the result object is not
27+
// eslint-disable-next-line react-hooks/exhaustive-deps
28+
}, [shouldRefetch])
2229

2330
return httpQueryResult
2431
}

app/src/resources/client_data/audit/useClientDataLogDeletion.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useCallback } from 'react'
1+
import { useCallback, useEffect } from 'react'
22

33
import { useClientData, useUpdateClientData } from '@opentrons/react-api-client'
44

@@ -27,9 +27,14 @@ export function useClientDataLogDeletion(
2727
queryOptionsNotify
2828
)
2929

30-
if (shouldRefetch) {
31-
void httpQueryResult.refetch()
32-
}
30+
useEffect(() => {
31+
if (shouldRefetch) {
32+
void httpQueryResult.refetch()
33+
}
34+
35+
// refetch is stable, the result object is not
36+
// eslint-disable-next-line react-hooks/exhaustive-deps
37+
}, [shouldRefetch])
3338

3439
const { data } = httpQueryResult
3540

app/src/resources/client_data/encryptionKeys/useNotifyClientDataEncryptionKeys.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { useEffect } from 'react'
2+
13
import { useClientData } from '@opentrons/react-api-client'
24

35
import { useNotifyDataReady } from '../../useNotifyDataReady'
@@ -24,9 +26,14 @@ export function useNotifyClientDataEncryptionKeys(
2426
queryOptionsNotify
2527
)
2628

27-
if (shouldRefetch) {
28-
void httpQueryResult.refetch()
29-
}
29+
useEffect(() => {
30+
if (shouldRefetch) {
31+
void httpQueryResult.refetch()
32+
}
33+
34+
// refetch is stable, the result object is not
35+
// eslint-disable-next-line react-hooks/exhaustive-deps
36+
}, [shouldRefetch])
3037

3138
return httpQueryResult
3239
}

app/src/resources/client_data/lpc/useNotifyClientDataLPC.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { useEffect } from 'react'
2+
13
import { useClientData } from '@opentrons/react-api-client'
24

35
import { useNotifyDataReady } from '../../useNotifyDataReady'
@@ -25,9 +27,14 @@ export function useNotifyClientDataLPC(
2527
queryOptionsNotify
2628
)
2729

28-
if (shouldRefetch) {
29-
void httpQueryResult.refetch()
30-
}
30+
useEffect(() => {
31+
if (shouldRefetch) {
32+
void httpQueryResult.refetch()
33+
}
34+
35+
// refetch is stable, the result object is not
36+
// eslint-disable-next-line react-hooks/exhaustive-deps
37+
}, [shouldRefetch])
3138

3239
return httpQueryResult
3340
}

app/src/resources/client_data/recovery/useNotifyClientDataRecovery.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { useEffect } from 'react'
2+
13
import { useClientData } from '@opentrons/react-api-client'
24

35
import { useNotifyDataReady } from '../../useNotifyDataReady'
@@ -24,9 +26,14 @@ export function useNotifyClientDataRecovery(
2426
queryOptionsNotify
2527
)
2628

27-
if (shouldRefetch) {
28-
void httpQueryResult.refetch()
29-
}
29+
useEffect(() => {
30+
if (shouldRefetch) {
31+
void httpQueryResult.refetch()
32+
}
33+
34+
// refetch is stable, the result object is not
35+
// eslint-disable-next-line react-hooks/exhaustive-deps
36+
}, [shouldRefetch])
3037

3138
return httpQueryResult
3239
}

app/src/resources/dataFiles/useNotifyImageFileQuery.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { useEffect } from 'react'
2+
13
import { useImageFileQuery } from '@opentrons/react-api-client'
24

35
import { useNotifyDataReady } from '../useNotifyDataReady'
@@ -17,9 +19,14 @@ export function useNotifyImageFileQuery(
1719

1820
const httpQueryResult = useImageFileQuery(runId, queryOptionsNotify)
1921

20-
if (shouldRefetch) {
21-
void httpQueryResult.refetch()
22-
}
22+
useEffect(() => {
23+
if (shouldRefetch) {
24+
void httpQueryResult.refetch()
25+
}
26+
27+
// refetch is stable, the result object is not
28+
// eslint-disable-next-line react-hooks/exhaustive-deps
29+
}, [shouldRefetch])
2330

2431
return httpQueryResult
2532
}

app/src/resources/deck_configuration/useNotifyDeckConfigurationQuery.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { useEffect } from 'react'
2+
13
import { useDeckConfigurationQuery } from '@opentrons/react-api-client'
24

35
import { useNotifyDataReady } from '../useNotifyDataReady'
@@ -16,9 +18,14 @@ export function useNotifyDeckConfigurationQuery(
1618

1719
const httpQueryResult = useDeckConfigurationQuery(queryOptionsNotify)
1820

19-
if (shouldRefetch) {
20-
void httpQueryResult.refetch()
21-
}
21+
useEffect(() => {
22+
if (shouldRefetch) {
23+
void httpQueryResult.refetch()
24+
}
25+
26+
// refetch is stable, the result object is not
27+
// eslint-disable-next-line react-hooks/exhaustive-deps
28+
}, [shouldRefetch])
2229

2330
return httpQueryResult
2431
}

app/src/resources/labware_offsets/useNotifySearchLabwareOffsets.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { useEffect } from 'react'
2+
13
import { useSearchLabwareOffsets } from '@opentrons/react-api-client'
24

35
import { useNotifyDataReady } from '../useNotifyDataReady'
@@ -24,9 +26,14 @@ export function useNotifySearchLabwareOffsets(
2426

2527
const httpQueryResult = useSearchLabwareOffsets(request, queryOptionsNotify)
2628

27-
if (shouldRefetch) {
28-
void httpQueryResult.refetch()
29-
}
29+
useEffect(() => {
30+
if (shouldRefetch) {
31+
void httpQueryResult.refetch()
32+
}
33+
34+
// refetch is stable, the result object is not
35+
// eslint-disable-next-line react-hooks/exhaustive-deps
36+
}, [shouldRefetch])
3037

3138
return httpQueryResult
3239
}

app/src/resources/maintenance_runs/notifications/useNotifyCurrentMaintenanceRun.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { useEffect } from 'react'
2+
13
import { useCurrentMaintenanceRun } from '@opentrons/react-api-client'
24

35
import { useNotifyDataReady } from '../../useNotifyDataReady'
@@ -16,9 +18,14 @@ export function useNotifyCurrentMaintenanceRun(
1618

1719
const httpQueryResult = useCurrentMaintenanceRun(queryOptionsNotify)
1820

19-
if (shouldRefetch) {
20-
void httpQueryResult.refetch()
21-
}
21+
useEffect(() => {
22+
if (shouldRefetch) {
23+
void httpQueryResult.refetch()
24+
}
25+
26+
// refetch is stable, the result object is not
27+
// eslint-disable-next-line react-hooks/exhaustive-deps
28+
}, [shouldRefetch])
2229

2330
return httpQueryResult
2431
}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
import { renderHook } from '@testing-library/react'
2+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
3+
4+
import { useRunQuery } from '@opentrons/react-api-client'
5+
6+
import { useNotifyDataReady } from '/app/resources/useNotifyDataReady'
7+
8+
import { useNotifyRunQuery } from '../useNotifyRunQuery'
9+
10+
vi.mock('@opentrons/react-api-client')
11+
vi.mock('/app/resources/useNotifyDataReady')
12+
13+
const MOCK_RUN_ID = 'run-123'
14+
const MOCK_OPTIONS = { staleTime: 5000 }
15+
16+
describe('useNotifyRunQuery', () => {
17+
const refetch = vi.fn()
18+
const queryOptionsNotify = { ...MOCK_OPTIONS, refetchInterval: false }
19+
20+
beforeEach(() => {
21+
vi.mocked(useNotifyDataReady).mockReturnValue({
22+
shouldRefetch: false,
23+
queryOptionsNotify,
24+
} as any)
25+
vi.mocked(useRunQuery).mockReturnValue({
26+
refetch,
27+
} as any)
28+
})
29+
30+
afterEach(() => {
31+
vi.clearAllMocks()
32+
})
33+
34+
it('should pass notify options through to useRunQuery', () => {
35+
renderHook(() => useNotifyRunQuery(MOCK_RUN_ID, MOCK_OPTIONS))
36+
37+
expect(useNotifyDataReady).toHaveBeenCalledWith({
38+
topic: `robot-server/runs/${MOCK_RUN_ID}`,
39+
options: MOCK_OPTIONS,
40+
hostOverride: undefined,
41+
})
42+
expect(useRunQuery).toHaveBeenCalledWith(
43+
MOCK_RUN_ID,
44+
queryOptionsNotify,
45+
undefined
46+
)
47+
})
48+
49+
it('should refetch in an effect when shouldRefetch is true, not during render', () => {
50+
vi.mocked(useNotifyDataReady).mockReturnValue({
51+
shouldRefetch: true,
52+
queryOptionsNotify,
53+
} as any)
54+
vi.mocked(useRunQuery).mockImplementation(() => {
55+
// useRunQuery runs during render; refetch must not have been called yet.
56+
expect(refetch).not.toHaveBeenCalled()
57+
return { refetch } as any
58+
})
59+
60+
renderHook(() => useNotifyRunQuery(MOCK_RUN_ID, MOCK_OPTIONS))
61+
62+
expect(refetch).toHaveBeenCalledTimes(1)
63+
})
64+
65+
it('should not refetch when shouldRefetch is false', () => {
66+
renderHook(() => useNotifyRunQuery(MOCK_RUN_ID, MOCK_OPTIONS))
67+
68+
expect(refetch).not.toHaveBeenCalled()
69+
})
70+
71+
it('should not refetch when runId is null', () => {
72+
vi.mocked(useNotifyDataReady).mockReturnValue({
73+
shouldRefetch: true,
74+
queryOptionsNotify,
75+
} as any)
76+
77+
renderHook(() => useNotifyRunQuery(null, MOCK_OPTIONS))
78+
79+
expect(refetch).not.toHaveBeenCalled()
80+
})
81+
82+
it('should not refetch when runId is the string "null"', () => {
83+
vi.mocked(useNotifyDataReady).mockReturnValue({
84+
shouldRefetch: true,
85+
queryOptionsNotify,
86+
} as any)
87+
88+
renderHook(() => useNotifyRunQuery('null', MOCK_OPTIONS))
89+
90+
expect(refetch).not.toHaveBeenCalled()
91+
})
92+
93+
it('should refetch when shouldRefetch becomes true after a rerender', () => {
94+
const { rerender } = renderHook(() =>
95+
useNotifyRunQuery(MOCK_RUN_ID, MOCK_OPTIONS)
96+
)
97+
98+
expect(refetch).not.toHaveBeenCalled()
99+
100+
vi.mocked(useNotifyDataReady).mockReturnValue({
101+
shouldRefetch: true,
102+
queryOptionsNotify,
103+
} as any)
104+
rerender()
105+
106+
expect(refetch).toHaveBeenCalledTimes(1)
107+
})
108+
})

0 commit comments

Comments
 (0)