diff --git a/packages/hooks/src/useFullscreen/__tests__/index.test.ts b/packages/hooks/src/useFullscreen/__tests__/index.test.ts index 96345e25a3..c453317175 100644 --- a/packages/hooks/src/useFullscreen/__tests__/index.test.ts +++ b/packages/hooks/src/useFullscreen/__tests__/index.test.ts @@ -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', { @@ -42,6 +45,7 @@ describe('useFullscreen', () => { afterEach(() => { document.body.removeChild(targetEl); events.fullscreenchange.clear(); + globalHook?.unmount(); }); afterAll(() => { @@ -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', () => { diff --git a/packages/hooks/src/useFullscreen/demo/demo4.tsx b/packages/hooks/src/useFullscreen/demo/demo4.tsx new file mode 100644 index 0000000000..bdcb12884a --- /dev/null +++ b/packages/hooks/src/useFullscreen/demo/demo4.tsx @@ -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 ( +
+### Coexist with other full screen operations
+
+
+
## API
```typescript
diff --git a/packages/hooks/src/useFullscreen/index.ts b/packages/hooks/src/useFullscreen/index.ts
index 942a7998bf..3220ca8fb1 100644
--- a/packages/hooks/src/useFullscreen/index.ts
+++ b/packages/hooks/src/useFullscreen/index.ts
@@ -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';
@@ -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) {
@@ -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);
@@ -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 = () => {
@@ -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);
}
@@ -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,
diff --git a/packages/hooks/src/useFullscreen/index.zh-CN.md b/packages/hooks/src/useFullscreen/index.zh-CN.md
index fae61633b1..503bd58007 100644
--- a/packages/hooks/src/useFullscreen/index.zh-CN.md
+++ b/packages/hooks/src/useFullscreen/index.zh-CN.md
@@ -21,6 +21,10 @@ nav:
+### 与其它全屏操作共存
+
+
+
## API
```typescript