Skip to content

Commit

Permalink
fix(useintersectionobserver): remove ref from props and createRef in …
Browse files Browse the repository at this point in the history
…useIntersectionObserver (#516)

* fix(useintersectionobserver): remove ref from props and createRef in useIntersectionObserver

* fix(useintersectionobserver): change return, use variable
  • Loading branch information
LuckyFBB authored Dec 27, 2024
1 parent 96edb4d commit fcc232b
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 31 deletions.
7 changes: 3 additions & 4 deletions src/image/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { CSSProperties, useRef } from 'react';
import React, { CSSProperties } from 'react';
import { Spin } from 'antd';

import useIntersectionObserver from '../useIntersectionObserver';
Expand Down Expand Up @@ -52,8 +52,7 @@ const ImageComponent = (props: IProps) => {

const LazyImage = (props: IProps) => {
const { src, ...rest } = props;
const imgRef = useRef<HTMLImageElement>(null);
useIntersectionObserver(([entry]) => {
const imgRef = useIntersectionObserver<HTMLImageElement>(([entry]) => {
const { target, isIntersecting } = entry;
if (isIntersecting) {
const _target = target as HTMLImageElement;
Expand All @@ -62,7 +61,7 @@ const LazyImage = (props: IProps) => {
_target.style.opacity = '1';
};
}
}, imgRef);
});
return <img ref={imgRef} {...rest} data-src={src} />;
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { RefObject } from 'react';
import { act, renderHook } from '@testing-library/react-hooks';

import useIntersectionObserver from '../index';
Expand Down Expand Up @@ -31,25 +30,35 @@ describe('useIntersectionObserver', () => {
});

it('should observe target element and disconnect on unmount', () => {
const ref = { current: document.createElement('div') };
const callback = jest.fn();
const options = { threshold: 0, root: null, rootMargin: '0%' };
const { unmount } = renderHook(() => useIntersectionObserver(callback, ref, options));

const divElement = document.createElement('div');
document.body.appendChild(divElement);

const { unmount } = renderHook(() => {
const ref = useIntersectionObserver(callback, options);
ref.current = divElement;
return ref;
});
expect(window.IntersectionObserver).toHaveBeenCalledWith(expect.any(Function), options);
expect(observeMock).toHaveBeenCalledWith(ref.current);
expect(observeMock).toHaveBeenCalledWith(divElement);
act(() => {
unmount();
});
expect(disconnectMock).toHaveBeenCalled();
});

it('should not observe target element if not provided', () => {
it('should not observe target element if ref is null', () => {
const callback = jest.fn();
const options = { threshold: 0, root: null, rootMargin: '0%' };
const { unmount } = renderHook(() =>
useIntersectionObserver(callback, null as unknown as RefObject<Element>, options)
);
expect(window.IntersectionObserver).toHaveBeenCalledWith(expect.any(Function), options);

const { unmount } = renderHook(() => {
const ref = useIntersectionObserver(callback, options);
ref.current = null;
return ref;
});

expect(observeMock).not.toHaveBeenCalled();
act(() => {
unmount();
Expand Down
8 changes: 3 additions & 5 deletions src/useIntersectionObserver/demos/basic.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
import React, { useRef } from 'react';
import React from 'react';

import useIntersectionObserver from '..';

const Basic = () => {
const divRef = useRef<HTMLDivElement>(null);

const handleObserverCb = ([entry]: IntersectionObserverEntry[]) => {
if (entry.isIntersecting) alert('hi, 我展示了');
};

useIntersectionObserver(handleObserverCb, divRef);
const ref = useIntersectionObserver<HTMLDivElement>(handleObserverCb);

return (
<div style={{ height: 300, overflow: 'scroll' }}>
<div style={{ height: 330 }}>占位,往下滑动</div>
<div ref={divRef}>
<div ref={ref}>
<div>展示了</div>
</div>
</div>
Expand Down
6 changes: 2 additions & 4 deletions src/useIntersectionObserver/demos/imgLazy.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import React, { useRef } from 'react';
import React from 'react';

import useIntersectionObserver from '..';

const Basic = () => {
const imgRef = useRef<HTMLImageElement>(null);

const handleObserverCb = ([entry]: IntersectionObserverEntry[]) => {
const { target, isIntersecting } = entry;
if (isIntersecting) {
Expand All @@ -16,7 +14,7 @@ const Basic = () => {
}
};

useIntersectionObserver(handleObserverCb, imgRef, {});
const imgRef = useIntersectionObserver<HTMLImageElement>(handleObserverCb);

return (
<div style={{ height: 300, overflow: 'scroll' }}>
Expand Down
21 changes: 12 additions & 9 deletions src/useIntersectionObserver/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { RefObject, useEffect, useState } from 'react';
import { MutableRefObject, useEffect, useRef, useState } from 'react';

const useIntersectionObserver = (
const useIntersectionObserver = <T extends Element>(
callback: IntersectionObserverCallback,
target: RefObject<Element>,
options: IntersectionObserverInit & { freezeOnceVisible?: boolean } = {}
) => {
const ref = useRef<T | null>(null);

const { threshold = 0, root = null, rootMargin = '0%', freezeOnceVisible = false } = options;
const [entry, setEntry] = useState<IntersectionObserverEntry>();
const frozen = entry?.isIntersecting && freezeOnceVisible;
Expand All @@ -18,17 +19,17 @@ const useIntersectionObserver = (
};

useEffect(() => {
const node = target?.current; // DOM Ref
const node = ref.current;
const hasIOSupport = !!window.IntersectionObserver;

if (frozen || !node) return;
if (!hasIOSupport) {
// 如果不支持 IntersectionObserver 执行一个默认行为
const callbackEntry = {
boundingClientRect: node?.getBoundingClientRect() ?? null,
intersectionRatio: node ? 1 : 0,
intersectionRect: node?.getBoundingClientRect() ?? null,
isIntersecting: !!node,
boundingClientRect: node.getBoundingClientRect() ?? null,
intersectionRatio: 1,
intersectionRect: node.getBoundingClientRect() ?? null,
isIntersecting: true,
rootBounds: null,
target: node,
time: Date.now(),
Expand All @@ -40,7 +41,9 @@ const useIntersectionObserver = (

observer.observe(node);
return () => observer.disconnect();
}, [target?.current, JSON.stringify(threshold), root, rootMargin, frozen]);
}, [JSON.stringify(threshold), root, rootMargin, frozen]);

return ref as MutableRefObject<T | null>;
};

export default useIntersectionObserver;

0 comments on commit fcc232b

Please sign in to comment.