Skip to content

Commit 0044ae4

Browse files
committed
fix: ask canReload only when a reload is due, and reload builds found while hidden
The guard ran in checkVersion's default parameter, before the fetch and on every poll, so its answer could be stale by the time a reload happened. A check that resolved after the tab went to the background never reloaded, because visibilitychange had already fired. Polling restarts only when `duration` changes, since `auto` is read at check time.
1 parent 423801f commit 0044ae4

2 files changed

Lines changed: 42 additions & 8 deletions

File tree

‎src/ClearBrowserCacheBoundary.tsx‎

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -203,11 +203,7 @@ export class ClearBrowserCacheBoundary extends React.Component<
203203
}
204204

205205
componentDidUpdate(prevProps: ClearBrowserCacheBoundaryProps) {
206-
const { duration, auto } = this.props;
207-
const pollingChanged =
208-
duration !== prevProps.duration || auto !== prevProps.auto;
209-
210-
if (pollingChanged && document.hasFocus()) {
206+
if (this.props.duration !== prevProps.duration && document.hasFocus()) {
211207
this.startVersionCheck();
212208
}
213209

@@ -389,9 +385,20 @@ export class ClearBrowserCacheBoundary extends React.Component<
389385
}
390386
}
391387

388+
// The guard is asked only once a newer build is known, so it sees the page
389+
// as it is at reload time and is not called on every poll.
390+
unattendedReloadAllowed() {
391+
const { auto, reloadWhenHidden } = this.props;
392+
const wanted =
393+
Boolean(auto) ||
394+
(Boolean(reloadWhenHidden) && document.visibilityState === 'hidden');
395+
396+
return wanted && this.reloadAllowed();
397+
}
398+
392399
checkVersion = async ({
393-
auto = (this.props.auto ?? false) && this.reloadAllowed()
394-
} = {}): Promise<CheckResult> => {
400+
auto
401+
}: { auto?: boolean } = {}): Promise<CheckResult> => {
395402
this.lastCheckAt = Date.now();
396403

397404
try {
@@ -404,7 +411,7 @@ export class ClearBrowserCacheBoundary extends React.Component<
404411

405412
const isLatestVersion = latestVersion === this.appVersion;
406413

407-
if (!isLatestVersion && auto) {
414+
if (!isLatestVersion && (auto ?? this.unattendedReloadAllowed())) {
408415
await this.clearCacheAndReload(latestVersion);
409416
return 'reloading';
410417
}

‎test/smoothUpdates.test.tsx‎

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,22 @@ describe('reloadWhenHidden', () => {
112112
);
113113
});
114114

115+
it('reloads when a check finds a new build after the tab went hidden', async () => {
116+
mockFetch(
117+
() => metaResponse('v1'),
118+
() => metaResponse('v2')
119+
);
120+
121+
renderBoundary({ duration: 10, reloadWhenHidden: true });
122+
await screen.findByTestId('isLatestVersion');
123+
setVisibility('hidden');
124+
fireEvent.focus(window);
125+
126+
await waitFor(() =>
127+
expect(window.localStorage.getItem(STORAGE_KEY)).toBe('v2')
128+
);
129+
});
130+
115131
it('leaves a current build alone', async () => {
116132
mockFetch(() => metaResponse('v1'));
117133
const caches = { keys: vi.fn(async () => []), delete: vi.fn() };
@@ -198,6 +214,17 @@ describe('canReload', () => {
198214
);
199215
});
200216

217+
it('does not ask the guard while the build is current', async () => {
218+
mockFetch(() => metaResponse('v1'));
219+
const canReload = vi.fn(() => true);
220+
221+
renderBoundary({ duration: 10, auto: true, canReload });
222+
await screen.findByTestId('isLatestVersion');
223+
await wait(40);
224+
225+
expect(canReload).not.toHaveBeenCalled();
226+
});
227+
201228
it('reloads once the guard allows it', async () => {
202229
mockFetch(
203230
() => metaResponse('v1'),

0 commit comments

Comments
 (0)