Skip to content

Commit 0bfa5fb

Browse files
committed
Use hook in component implementation. Fixes #24.
1 parent a6ac88a commit 0bfa5fb

File tree

6 files changed

+52
-254
lines changed

6 files changed

+52
-254
lines changed

package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "react-bottom-scroll-listener",
3-
"version": "4.0.0-beta-1",
3+
"version": "4.0.0",
44
"description": "A simple React component that lets you listen for when you have scrolled to the bottom.",
55
"repository": "https://github.com/karl-run/react-bottom-scroll-listener",
66
"keywords": [
@@ -58,11 +58,14 @@
5858
"eslint-config-prettier": "^6.7.0",
5959
"eslint-config-standard": "^14.1.0",
6060
"eslint-config-standard-react": "^9.2.0",
61+
"eslint-plugin-flowtype": "^4.7.0",
6162
"eslint-plugin-import": "^2.18.2",
63+
"eslint-plugin-jsx-a11y": "^6.2.3",
6264
"eslint-plugin-node": "^11.0.0",
6365
"eslint-plugin-prettier": "^3.1.1",
6466
"eslint-plugin-promise": "^4.2.1",
6567
"eslint-plugin-react": "^7.17.0",
68+
"eslint-plugin-react-hooks": "^4.0.0",
6669
"eslint-plugin-standard": "^4.0.1",
6770
"gh-pages": "^2.2.0",
6871
"microbundle-crl": "^0.13.10",

src/component/__snapshots__/index.test.tsx.snap

Lines changed: 0 additions & 25 deletions
This file was deleted.

src/component/index.test.tsx

Lines changed: 0 additions & 137 deletions
This file was deleted.

src/component/index.tsx

Lines changed: 33 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,27 @@
1-
/**
2-
* @class BottomScrollListener
3-
*
4-
* A simple React component that lets you listen for when you have scrolled to the bottom.
5-
*
6-
*/
1+
import React from 'react'
72

8-
import debounce from 'lodash.debounce'
9-
import React, { Component } from 'react'
3+
import useBottomScrollListener, { DebounceOptions } from '../hook'
104

115
export interface Props {
12-
/** Required callback that will be invoked when scrolled to bottom */
6+
/**
7+
* Required callback that will be invoked when scrolled to bottom
8+
*/
139
onBottom: () => void
1410

15-
/** Optional debounce in milliseconds, defaults to 200ms */
16-
debounce: number
11+
/**
12+
* Offset from bottom of page in pixels. E.g. 300 will trigger onBottom 300px from the bottom of the page
13+
*/
14+
offset?: number
1715

18-
/** Offset from bottom of page in pixels. E.g. 300 will trigger onBottom 300px from the bottom of the page */
19-
offset: number
16+
/**
17+
* Optional debounce in milliseconds, defaults to 200ms
18+
*/
19+
debounce?: number
20+
21+
/**
22+
* Options passed to lodash.debounce, see https://lodash.com/docs/4.17.15#debounce
23+
*/
24+
debounceOptions?: DebounceOptions
2025

2126
/**
2227
* Optional children to be rendered.
@@ -27,82 +32,21 @@ export interface Props {
2732
children?: React.ReactNode | (<T extends HTMLElement>(ref: React.Ref<T>) => React.ReactNode)
2833
}
2934

30-
class BottomScrollListener extends Component<Props> {
31-
public static defaultProps = {
32-
debounce: 200,
33-
offset: 0,
34-
}
35-
36-
private optionalScrollContainerRef: React.RefObject<HTMLElement> = React.createRef()
37-
38-
public constructor(props: Props) {
39-
super(props)
40-
41-
if (props.debounce) {
42-
this.handleOnScroll = debounce(this.handleOnScroll.bind(this), props.debounce, { trailing: true })
43-
} else {
44-
this.handleOnScroll = this.handleOnScroll.bind(this)
45-
}
46-
}
47-
48-
public componentDidMount() {
49-
if (this.props.children instanceof Function) {
50-
if (this.optionalScrollContainerRef.current) {
51-
this.optionalScrollContainerRef.current.addEventListener('scroll', this.handleOnScroll)
52-
} else {
53-
throw Error(
54-
'Unable to use scroll container: Ref to child not available, did you pass the ref prop to an element?',
55-
)
56-
}
57-
} else {
58-
document.addEventListener('scroll', this.handleOnScroll)
59-
}
60-
}
61-
62-
public componentWillUnmount() {
63-
if (this.props.children instanceof Function) {
64-
if (this.optionalScrollContainerRef.current) {
65-
this.optionalScrollContainerRef.current.removeEventListener('scroll', this.handleOnScroll)
66-
} else {
67-
throw Error('Unable to clean up scroll container: Ref has been unmounted prematurely.')
68-
}
69-
} else {
70-
document.removeEventListener('scroll', this.handleOnScroll)
71-
}
72-
}
73-
74-
public handleOnScroll() {
75-
if (this.props.children instanceof Function) {
76-
const scrollNode = this.optionalScrollContainerRef.current
77-
78-
if (scrollNode != null) {
79-
const scrollContainerBottomPosition = Math.round(scrollNode.scrollTop + scrollNode.clientHeight)
80-
const scrollPosition = Math.round(scrollNode.scrollHeight - this.props.offset)
81-
82-
if (scrollPosition <= scrollContainerBottomPosition) {
83-
this.props.onBottom()
84-
}
85-
}
86-
} else {
87-
const scrollNode = document.scrollingElement || document.documentElement
88-
const scrollContainerBottomPosition = Math.round(scrollNode.scrollTop + window.innerHeight)
89-
const scrollPosition = Math.round(scrollNode.scrollHeight - this.props.offset)
90-
91-
if (scrollPosition <= scrollContainerBottomPosition) {
92-
this.props.onBottom()
93-
}
94-
}
95-
}
96-
97-
public render() {
98-
if (!this.props.children) return null
99-
100-
if (this.props.children instanceof Function) {
101-
return this.props.children(this.optionalScrollContainerRef)
102-
} else {
103-
return this.props.children
104-
}
105-
}
35+
/**
36+
* A simple React component that lets you listen for when you have scrolled to the bottom.
37+
*/
38+
const BottomScrollListener = ({
39+
children,
40+
onBottom,
41+
offset,
42+
debounce,
43+
debounceOptions,
44+
}: Props): React.ReactNode | null => {
45+
const optionalScrollContainerRef = useBottomScrollListener(onBottom, offset, debounce, debounceOptions)
46+
47+
if (!children) return null
48+
else if (typeof children === 'function') return children(optionalScrollContainerRef)
49+
else return children
10650
}
10751

10852
export default BottomScrollListener

src/hook/index.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { useCallback, useEffect, useRef, useMemo } from 'react'
22
import lodashDebounce from 'lodash.debounce'
33

4-
type DebounceOptions = Parameters<typeof lodashDebounce>[2]
4+
export type DebounceOptions = Parameters<typeof lodashDebounce>[2]
55

66
const createCallback = (debounce: number, handleOnScroll: () => void, options: DebounceOptions): (() => void) => {
77
if (debounce) {
@@ -17,6 +17,7 @@ const createCallback = (debounce: number, handleOnScroll: () => void, options: D
1717
* @param onBottom Required callback that will be invoked when scrolled to bottom
1818
* @param offset Offset from bottom of page in pixels. E.g. 300 will trigger onBottom 300px from the bottom of the page
1919
* @param debounce Optional debounce in milliseconds, defaults to 200ms
20+
* @param debounceOptions Options passed to lodash.debounce, see https://lodash.com/docs/4.17.15#debounce
2021
* @return React.MutableRefObject Optionally you can use this to pass to a element to use that as the scroll container
2122
*/
2223
function useBottomScrollListener<T extends HTMLElement>(

yarn.lock

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4166,6 +4166,13 @@ [email protected]:
41664166
dependencies:
41674167
lodash "^4.17.15"
41684168

4169+
eslint-plugin-flowtype@^4.7.0:
4170+
version "4.7.0"
4171+
resolved "https://registry.yarnpkg.com/eslint-plugin-flowtype/-/eslint-plugin-flowtype-4.7.0.tgz#903a6ea3eb5cbf4c7ba7fa73cc43fc39ab7e4a70"
4172+
integrity sha512-M+hxhSCk5QBEValO5/UqrS4UunT+MgplIJK5wA1sCtXjzBcZkpTGRwxmLHhGpbHcrmQecgt6ZL/KDdXWqGB7VA==
4173+
dependencies:
4174+
lodash "^4.17.15"
4175+
41694176
41704177
version "2.20.1"
41714178
resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.20.1.tgz#802423196dcb11d9ce8435a5fc02a6d3b46939b3"
@@ -4202,7 +4209,7 @@ eslint-plugin-import@^2.18.2:
42024209
read-pkg-up "^2.0.0"
42034210
resolve "^1.12.0"
42044211

4205-
4212+
[email protected], eslint-plugin-jsx-a11y@^6.2.3:
42064213
version "6.2.3"
42074214
resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.2.3.tgz#b872a09d5de51af70a97db1eea7dc933043708aa"
42084215
integrity sha512-CawzfGt9w83tyuVekn0GDPU9ytYtxyxyFZ3aSWROmnRRFQFT2BiPJd7jvRdzNDi6oLWaS2asMeYSNMjWTV4eNg==
@@ -4246,6 +4253,11 @@ eslint-plugin-react-hooks@^1.6.1:
42464253
resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-1.7.0.tgz#6210b6d5a37205f0b92858f895a4e827020a7d04"
42474254
integrity sha512-iXTCFcOmlWvw4+TOE8CLWj6yX1GwzT0Y6cUfHHZqWnSk144VmVIRcVGtUAzrLES7C798lmvnt02C7rxaOX1HNA==
42484255

4256+
eslint-plugin-react-hooks@^4.0.0:
4257+
version "4.0.0"
4258+
resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.0.0.tgz#81196b990043cde339e25c6662aeebe32ac52d01"
4259+
integrity sha512-YKBY+kilK5wrwIdQnCF395Ya6nDro3EAMoe+2xFkmyklyhF16fH83TrQOo9zbZIDxBsXFgBbywta/0JKRNFDkw==
4260+
42494261
[email protected], eslint-plugin-react@^7.17.0:
42504262
version "7.19.0"
42514263
resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.19.0.tgz#6d08f9673628aa69c5559d33489e855d83551666"

0 commit comments

Comments
 (0)