Skip to content

Commit

Permalink
fix(useFullscreen): always listen to fullscreen change and dynamicall…
Browse files Browse the repository at this point in the history
…y set the initial value (#1996)

* fix: always listen to fullscreen change

* refactor: restore original code

* refactor: optimize code

* docs: remove useless comment

* fix: though closure

* refactor: simplify getIsFullscreen

* refactor: update

* docs: remove extra comment

* docs: add demo4

---------

Co-authored-by: 云泥 <liuyibo@xylink.com>
Co-authored-by: liuyib <1656081615@qq.com>
  • Loading branch information
3 people authored Jul 12, 2023
1 parent 9d60990 commit 80f7226
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 34 deletions.
17 changes: 11 additions & 6 deletions packages/hooks/src/useFullscreen/__tests__/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,20 @@ import useFullscreen from '../index';
import type { Options } from '../index';
import type { BasicTarget } from '../../utils/domTarget';

const targetEl = document.createElement('div');
let globalHook: any;
let targetEl: any;
const events = {
fullscreenchange: new Set(),
fullscreenerror: new Set(),
};

const setup = (target: BasicTarget, options?: Options) =>
renderHook(() => useFullscreen(target, options));
const setup = (target: BasicTarget, options?: Options) => {
globalHook = renderHook(() => useFullscreen(target, options));
return globalHook;
};

describe('useFullscreen', () => {
beforeEach(() => {
targetEl = document.createElement('div');
document.body.appendChild(targetEl);
jest.spyOn(HTMLElement.prototype, 'requestFullscreen').mockImplementation(() => {
Object.defineProperty(document, 'fullscreenElement', {
Expand Down Expand Up @@ -42,6 +45,7 @@ describe('useFullscreen', () => {
afterEach(() => {
document.body.removeChild(targetEl);
events.fullscreenchange.clear();
globalHook?.unmount();
});

afterAll(() => {
Expand Down Expand Up @@ -163,10 +167,11 @@ describe('useFullscreen', () => {
});

it('enterFullscreen should not work when target is not element', () => {
const { result } = setup(null);
const onEnter = jest.fn();
const { result } = setup(null, { onEnter });
const { enterFullscreen } = result.current[1];
enterFullscreen();
expect(events.fullscreenchange.size).toBe(0);
expect(onEnter).not.toBeCalled();
});

it('should remove event listener when unmount', () => {
Expand Down
39 changes: 39 additions & 0 deletions packages/hooks/src/useFullscreen/demo/demo4.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* title: Coexist with other full screen operations
* desc: The element's full screen may be modified by other scripts, don't worry, ahooks can work with them.
*
* title.zh-CN: 与其它全屏操作共存
* desc.zh-CN: 元素的全屏情况可能被其它脚本修改,不用担心,ahooks 可以与它们共存。
*/

import React, { useRef } from 'react';
import { useFullscreen } from 'ahooks';

function vanillaToggleFullscreen(element) {
const isFullscreen = !!document.fullscreenElement;

if (isFullscreen) {
document.exitFullscreen();
} else {
element.requestFullscreen();
}
}

export default () => {
const ref = useRef(null);
const [isFullscreen, { toggleFullscreen }] = useFullscreen(ref);

return (
<div ref={ref} style={{ background: 'white' }}>
<div style={{ marginBottom: 16 }}>{isFullscreen ? 'Fullscreen' : 'Not fullscreen'}</div>
<div>
<button style={{ marginRight: '8px' }} onClick={toggleFullscreen}>
ahooks toggleFullscreen
</button>
<button onClick={() => vanillaToggleFullscreen(ref.current)}>
vanilla toggleFullscreen
</button>
</div>
</div>
);
};
4 changes: 4 additions & 0 deletions packages/hooks/src/useFullscreen/index.en-US.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ manages DOM full screen.

<code src="./demo/demo3.tsx" />

### Coexist with other full screen operations

<code src="./demo/demo4.tsx" />

## API

```typescript
Expand Down
64 changes: 36 additions & 28 deletions packages/hooks/src/useFullscreen/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { useState } from 'react';
import { useEffect, useState, useRef } from 'react';
import screenfull from 'screenfull';
import useLatest from '../useLatest';
import useMemoizedFn from '../useMemoizedFn';
import useUnmount from '../useUnmount';
import type { BasicTarget } from '../utils/domTarget';
import { getTargetElement } from '../utils/domTarget';
import { isBoolean } from '../utils';
Expand All @@ -26,7 +25,18 @@ const useFullscreen = (target: BasicTarget, options?: Options) => {
const onExitRef = useLatest(onExit);
const onEnterRef = useLatest(onEnter);

const [state, setState] = useState(false);
// The state of full screen may be changed by other scripts/components,
// so the initial value needs to be computed dynamically.
const [state, setState] = useState(getIsFullscreen);
const stateRef = useRef(getIsFullscreen());

function getIsFullscreen() {
return (
screenfull.isEnabled &&
!!screenfull.element &&
screenfull.element === getTargetElement(target)
);
}

const invokeCallback = (fullscreen: boolean) => {
if (fullscreen) {
Expand All @@ -36,23 +46,20 @@ const useFullscreen = (target: BasicTarget, options?: Options) => {
}
};

// Memoized, otherwise it will be listened multiple times.
const onScreenfullChange = useMemoizedFn(() => {
if (screenfull.isEnabled) {
const el = getTargetElement(target);
const updateFullscreenState = (fullscreen: boolean) => {
// Prevent repeated calls when the state is not changed.
if (stateRef.current !== fullscreen) {
invokeCallback(fullscreen);
setState(fullscreen);
stateRef.current = fullscreen;
}
};

if (!screenfull.element) {
invokeCallback(false);
setState(false);
screenfull.off('change', onScreenfullChange);
} else {
const isFullscreen = screenfull.element === el;
const onScreenfullChange = () => {
const fullscreen = getIsFullscreen();

invokeCallback(isFullscreen);
setState(isFullscreen);
}
}
});
updateFullscreenState(fullscreen);
};

const togglePageFullscreen = (fullscreen: boolean) => {
const el = getTargetElement(target);
Expand Down Expand Up @@ -84,11 +91,7 @@ const useFullscreen = (target: BasicTarget, options?: Options) => {
}
}

// Prevent repeated calls when the state is not changed.
if (state !== fullscreen) {
invokeCallback(fullscreen);
setState(fullscreen);
}
updateFullscreenState(fullscreen);
};

const enterFullscreen = () => {
Expand All @@ -104,7 +107,6 @@ const useFullscreen = (target: BasicTarget, options?: Options) => {
if (screenfull.isEnabled) {
try {
screenfull.request(el);
screenfull.on('change', onScreenfullChange);
} catch (error) {
console.error(error);
}
Expand Down Expand Up @@ -134,11 +136,17 @@ const useFullscreen = (target: BasicTarget, options?: Options) => {
}
};

useUnmount(() => {
if (screenfull.isEnabled && !pageFullscreen) {
screenfull.off('change', onScreenfullChange);
useEffect(() => {
if (!screenfull.isEnabled || pageFullscreen) {
return;
}
});

screenfull.on('change', onScreenfullChange);

return () => {
screenfull.off('change', onScreenfullChange);
};
}, []);

return [
state,
Expand Down
4 changes: 4 additions & 0 deletions packages/hooks/src/useFullscreen/index.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ nav:

<code src="./demo/demo3.tsx" />

### 与其它全屏操作共存

<code src="./demo/demo4.tsx" />

## API

```typescript
Expand Down

0 comments on commit 80f7226

Please sign in to comment.