Skip to content

Commit

Permalink
feat: add useScroll hook
Browse files Browse the repository at this point in the history
  • Loading branch information
streamich authored Mar 23, 2019
2 parents e49a507 + 584bd7e commit a92e9b2
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 5 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@
- [`useMotion`](./docs/useMotion.md) — tracks state of device's motion sensor.
- [`useNetwork`](./docs/useNetwork.md) — tracks state of user's internet connection.
- [`useOrientation`](./docs/useOrientation.md) — tracks state of device's screen orientation.
- [`useScroll`](./docs/useScroll.md) — some HTML element's scroll position. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/sensors-usescroll--docs)

- [`useSize`](./docs/useSize.md) — tracks some HTML element's dimensions.
- [`useWindowScroll`](./docs/useWindowScroll.md) — tracks `Window` scroll position. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/sensors-usewindowscroll--docs)
- [`useWindowSize`](./docs/useWindowSize.md) — tracks `Window` dimensions. [![][img-demo]](https://codesandbox.io/s/m7ln22668)
Expand Down
21 changes: 21 additions & 0 deletions docs/useScroll.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# `useScroll`

React sensor hook that re-renders on when scroll position in a DOM element changes.

## Usage

```jsx
import {useScroll} from 'react-use';

const Demo = () => {
const element = React.useRef(null);
const {x, y} = useScroll(element);

return (
<div ref={element}>
<div>x: {x}</div>
<div>y: {y}</div>
</div>
);
};
```
35 changes: 35 additions & 0 deletions src/__stories__/useScroll.story.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import * as React from 'react';
import {storiesOf} from '@storybook/react';
import {useScroll} from '..';
import ShowDocs from '../util/ShowDocs';

const Demo = () => {
const element = React.useRef(null);
const {x, y} = useScroll(element);

return (
<>
<div>x: {x}</div>
<div>y: {y}</div>
<div
ref={element}
style={{
width: '400px',
height: '400px',
backgroundColor: 'whitesmoke',
overflow: 'scroll'
}}>

<div style={{width: '2000px', height: '2000px'}}>
Scroll me
</div>
</div>
</>
);
};

storiesOf('Sensors/useScroll', module)
.add('Docs', () => <ShowDocs md={require('../../docs/useScroll.md')} />)
.add('Demo', () =>
<Demo/>
)
10 changes: 5 additions & 5 deletions src/__stories__/useWindowScroll.story.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ const Demo = () => {

return (
<div style={{
width: "200vw",
height: "200vh"
width: '200vw',
height: '200vh'
}}>
<div style={{
position: "fixed",
position: 'fixed',
left: 0,
right: 0}}
>
right: 0
}}>
<div>x: {x}</div>
<div>y: {y}</div>
</div>
Expand Down
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import useOutsideClick from './useOutsideClick';
import usePromise from './usePromise';
import useRaf from './useRaf';
import useRefMounted from './useRefMounted';
import useScroll from './useScroll';
import useSessionStorage from './useSessionStorage';
import useSetState from './useSetState';
import useSize from './useSize';
Expand Down Expand Up @@ -90,6 +91,7 @@ export {
usePromise,
useRaf,
useRefMounted,
useScroll,
useSessionStorage,
useSetState,
useSize,
Expand Down
48 changes: 48 additions & 0 deletions src/useScroll.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import {useState, useEffect, useRef} from 'react';
import {isClient} from './util';

export interface State {
x: number;
y: number;
}

const useScroll = (ref): State => {
const frame = useRef(0);
const [state, setState] = useState<State>({
x: isClient ? window.scrollX : 0,
y: isClient ? window.scrollY : 0
});

useEffect(() => {
const handler = () => {

frame.current = requestAnimationFrame(() => {
setState({
x: ref.current.scrollLeft,
y: ref.current.scrollTop
});
});
}

if (ref && ref.current) {
ref.current.addEventListener('scroll', handler, {
capture: false,
passive: true
});
}

return () => {
if (frame.current) {
cancelAnimationFrame(frame.current);
}

if (ref && ref.current) {
ref.current.removeEventListener('scroll', handler);
}
};
}, [ref]);

return state;
}

export default useScroll

0 comments on commit a92e9b2

Please sign in to comment.