Skip to content

Commit

Permalink
Merge pull request #60 from ice-lab/refactor/useInViewport
Browse files Browse the repository at this point in the history
refactor: useInViewport api
  • Loading branch information
awmleer authored May 27, 2020
2 parents 6cdae0b + 17864e7 commit 9f37745
Show file tree
Hide file tree
Showing 6 changed files with 44 additions and 66 deletions.
13 changes: 3 additions & 10 deletions packages/hooks/src/useInViewport/__tests__/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,9 @@ describe('useInViewport', () => {
it('should be defined', () => {
expect(useInViewport).toBeDefined();
});
it('without argument ', () => {
const hook = renderHook(() => useInViewport());
expect(hook.result.current.length).toEqual(2);
expect(hook.result.current[0]).toEqual(false);
expect(hook.result.current[1].current).toEqual(undefined);
});

it('with argument', () => {
const hook = renderHook(() => useInViewport<HTMLBodyElement>(document.body));
expect(hook.result.current.length).toEqual(1);
// expect(hook.result.current[0]).toEqual(true);
expect(hook.result.current[0]).toEqual(false);
const hook = renderHook(() => useInViewport(document.body));
expect(hook.result.current).toEqual(false);
});
});
7 changes: 4 additions & 3 deletions packages/hooks/src/useInViewport/demo/demo1.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@
* desc.zh-CN: 使用 ref 监听节点在视图变化或者滚动时是否在可视范围之内
*/

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

export default () => {
const [inViewPort, ref] = useInViewport<HTMLDivElement>();
const ref = useRef();
const inViewPort = useInViewport(ref);
return (
<div>
<div ref={ref}>observer dom</div>
Expand Down
10 changes: 5 additions & 5 deletions packages/hooks/src/useInViewport/demo/demo2.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
/**
* title: Lazy load DOM element(used to subscibe to dom element renders after the hook)
* title: Pass in DOM element
* desc: Pass in a function that returns the DOM element.
*
* title.zh-CN: 懒加载(用于监听同一组件内后渲染节点)
* desc.zh-CN: 传入 function 来监听 dom 节点
* title.zh-CN: 传入 DOM 元素
* desc.zh-CN: 传入 function 并返回一个 dom 元素
*/

import React from 'react';
import {useInViewport} from 'ahooks';
import { useInViewport } from 'ahooks';

export default () => {
const [inViewPort] = useInViewport(() => document.querySelector('#demo2'));
const inViewPort = useInViewport(() => document.querySelector('#demo2'));
return (
<div>
<div id="demo2">observer dom</div>
Expand Down
19 changes: 9 additions & 10 deletions packages/hooks/src/useInViewport/index.en-US.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,26 +19,25 @@ A hook to subscribe DOM element visibility change

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

### Lazy load DOM element(used to subscibe to DOM element renders after the hook)
### Pass in DOM element

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


## API

```ts
const inViewPort = useInViewport(target);
```
const [ inViewPort, ref? ] = useInViewport(dom);
```

### Params

| Property | Description | Type | Default |
|---------|----------------------------------------------|------------------------|--------|
| target | DOM element or Ref Object | HTMLElement \| (() => HTMLElement) \| React.MutableRefObject | - |

### Result

| Property | Description | Type |
|----------|------------------------------------------|------------|
| inViewPort | Whether DOM elements are in the visible range | boolean |
| ref | when no param is passed, this ref will be listened | - |

### Params

| Property | Description | Type | Default |
|---------|----------------------------------------------|------------------------|--------|
| dom? | optional, if none is passed, this hook will subscibe to the ref that it returns | HTMLElement \| (() => HTMLElement) \| undefined | - |
36 changes: 11 additions & 25 deletions packages/hooks/src/useInViewport/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { useRef, useLayoutEffect, useState, MutableRefObject } from 'react';

import { useLayoutEffect, useState, MutableRefObject } from 'react';
import 'intersection-observer';
import { getTargetElement } from '../utils/dom';

type Arg = HTMLElement | (() => HTMLElement) | null;
type Target = HTMLElement | (() => HTMLElement) | MutableRefObject<HTMLElement>;
type InViewport = boolean | undefined;

function isInViewPort(el: HTMLElement): boolean {
Expand All @@ -24,27 +25,16 @@ function isInViewPort(el: HTMLElement): boolean {
return false;
}

function useInViewport<T extends HTMLElement = HTMLElement>(): [InViewport, MutableRefObject<T>];
function useInViewport<T extends HTMLElement = HTMLElement>(arg: Arg): [InViewport];
function useInViewport<T extends HTMLElement = HTMLElement>(
...args: [Arg] | []
): [InViewport, MutableRefObject<T>?] {
const element = useRef<T>();
const hasPassedInElement = args.length === 1;
const arg = useRef(args[0]);
[arg.current] = args;
function useInViewport(target: Target): InViewport {
const [inViewPort, setInViewport] = useState<InViewport>(() => {
const initDOM = typeof arg.current === 'function' ? arg.current() : arg.current;
const el = getTargetElement(target)

return isInViewPort(initDOM as HTMLElement);
return isInViewPort(el as HTMLElement);
});

useLayoutEffect(() => {
const passedInElement = typeof arg.current === 'function' ? arg.current() : arg.current;

const targetElement = hasPassedInElement ? passedInElement : element.current;

if (!targetElement) {
const el = getTargetElement(target);
if (!el) {
return () => {};
}

Expand All @@ -58,18 +48,14 @@ function useInViewport<T extends HTMLElement = HTMLElement>(
}
});

observer.observe(targetElement);
observer.observe(el as HTMLElement);

return () => {
observer.disconnect();
};
}, [element.current, typeof arg.current === 'function' ? undefined : arg.current]);

if (hasPassedInElement) {
return [inViewPort];
}
}, [typeof target === 'function' ? undefined : target]);

return [inViewPort, element as MutableRefObject<T>];
return inViewPort;
}

export default useInViewport;
25 changes: 12 additions & 13 deletions packages/hooks/src/useInViewport/index.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,33 +11,32 @@ legacy: /zh-CN/dom/use-in-viewport

# useInViewport

一个用于判断dom元素是否在可视范围之内的 Hook
一个用于判断 dom 元素是否在可视范围之内的 Hook

## 代码演示

### 基本用法

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

### 懒加载(用于监听同一组件内后渲染节点)
### 传入 DOM 元素

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

## API

```ts
const inViewPort = useInViewport(target);
```
const [ inViewPort, ref? ] = useInViewport(dom);
```

### Result

| 参数 | 说明 | 类型 |
|----------|------------------------------------------|------------|
| inViewPort | 判断dom元素是否在可视范围之内的标志 | boolean |
| ref | 当未传入任何参数时,将 ref 绑定给需监听的节点 | - |

### Params
### 参数

| 参数 | 说明 | 类型 | 默认值 |
|---------|----------------------------------------------|------------------------|--------|
| dom? | 可选项,如果未传入则会监听返回结果中的 ref,否则会监听传入的节点 | HTMLElement \| (() => HTMLElement) \| undefined | - |
| target | DOM element or Ref Object | HTMLElement \| (() => HTMLElement) \| React.MutableRefObject | - |

### 结果

| 参数 | 说明 | 类型 |
|----------|------------------------------------------|------------|
| inViewPort | 判断 dom 元素是否在可视范围之内的标志 | boolean |

0 comments on commit 9f37745

Please sign in to comment.