Skip to content

Commit 2caacaa

Browse files
author
Vincent Comby
committed
initial commit
1 parent ffb91db commit 2caacaa

File tree

9 files changed

+176
-75
lines changed

9 files changed

+176
-75
lines changed

README.md

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,34 @@
99
```bash
1010
npm install --save use-sync-scroll-hook
1111
```
12+
or
13+
```bash
14+
yarn add use-sync-scroll-hook
15+
```
1216

1317
## Usage
1418

1519
```jsx
16-
import React, { Component } from 'react'
17-
18-
import MyComponent from 'use-sync-scroll-hook'
19-
20-
class Example extends Component {
21-
render () {
22-
return (
23-
<MyComponent />
24-
)
25-
}
20+
import React, { useRef } from 'react'
21+
22+
import useSyncScroll from 'use-sync-scroll-hook'
23+
24+
export default function Example() {
25+
const headerRef = useRef()
26+
const bodyRef = useRef()
27+
28+
useSyncScroll([headerRef, bodyRef])
29+
30+
return (
31+
<div className="table">
32+
<div ref={headerRef} className="table-header">
33+
...
34+
</div>
35+
<div ref={bodyRef} className="table-body">
36+
...
37+
</div>
38+
</div>
39+
)
2640
}
2741
```
2842

example/package-lock.json

Lines changed: 2 additions & 13 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

example/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
"private": true,
77
"dependencies": {
88
"prop-types": "^15.6.2",
9-
"react": "^16.4.1",
10-
"react-dom": "^16.4.1",
9+
"react": "file:../node_modules/react",
10+
"react-dom": "file:../node_modules/react-dom",
1111
"react-scripts": "^1.1.4",
1212
"use-sync-scroll-hook": "file:.."
1313
},

example/src/App.js

Lines changed: 46 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,50 @@
1-
import React, { Component } from 'react'
1+
import React, { useRef } from 'react'
22

3-
import ExampleComponent from 'use-sync-scroll-hook'
3+
import useSyncScroll from 'use-sync-scroll-hook'
44

5-
export default class App extends Component {
6-
render () {
7-
return (
8-
<div>
9-
<ExampleComponent text='Modern React component module' />
5+
export default function App() {
6+
const headerRef = useRef()
7+
const bodyRef = useRef()
8+
9+
useSyncScroll([headerRef, bodyRef])
10+
11+
return (
12+
<div className="table">
13+
<div ref={headerRef} className="table-header">
14+
<div className="cell"> Header 1 </div>
15+
<div className="cell"> Header 2 </div>
16+
<div className="cell"> Header 3 </div>
17+
<div className="cell"> Header 4 </div>
18+
<div className="cell"> Header 5 </div>
19+
</div>
20+
<div className="separator">
21+
The body & header of table have their scroll position in sync.
22+
</div>
23+
<div ref={bodyRef} className="table-body">
24+
<div className="cell"> Cell 1 </div>
25+
<div className="cell"> Cell 2 </div>
26+
<div className="cell"> Cell 3 </div>
27+
<div className="cell"> Cell 4 </div>
28+
<div className="cell"> Cell 5 </div>
29+
30+
<div className="cell"> Cell 1 </div>
31+
<div className="cell"> Cell 2 </div>
32+
<div className="cell"> Cell 3 </div>
33+
<div className="cell"> Cell 4 </div>
34+
<div className="cell"> Cell 5 </div>
35+
36+
<div className="cell"> Cell 1 </div>
37+
<div className="cell"> Cell 2 </div>
38+
<div className="cell"> Cell 3 </div>
39+
<div className="cell"> Cell 4 </div>
40+
<div className="cell"> Cell 5 </div>
41+
42+
<div className="cell"> Cell 1 </div>
43+
<div className="cell"> Cell 2 </div>
44+
<div className="cell"> Cell 3 </div>
45+
<div className="cell"> Cell 4 </div>
46+
<div className="cell"> Cell 5 </div>
1047
</div>
11-
)
12-
}
48+
</div>
49+
)
1350
}

example/src/index.css

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,41 @@ body {
33
padding: 0;
44
font-family: sans-serif;
55
}
6+
7+
.table {
8+
width: 1000px;
9+
}
10+
11+
.table-header {
12+
display: grid;
13+
grid-template-columns: repeat(5, 500px);
14+
overflow: scroll;
15+
background: #638df1;
16+
color: white;
17+
}
18+
19+
.table-header .cell {
20+
border-right: 1px solid #6a6ac5;
21+
text-align: center;
22+
height: 50px;
23+
}
24+
25+
.separator {
26+
padding: 20px;
27+
text-align: center;
28+
}
29+
30+
.table-body {
31+
display: grid;
32+
grid-template-columns: repeat(5, 500px);
33+
overflow: scroll;
34+
background: whitesmoke;
35+
}
36+
37+
.table-body .cell {
38+
display: flex;
39+
justify-content: center;
40+
align-items: center;
41+
height: 50px;
42+
border-bottom: 1px solid grey;
43+
}

package.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "use-sync-scroll-hook",
3-
"version": "1.0.0",
3+
"version": "0.0.1",
44
"description": "React hook to synchronise the scroll position of multiple containers.",
55
"author": "slocka",
66
"license": "MIT",
@@ -23,8 +23,8 @@
2323
},
2424
"peerDependencies": {
2525
"prop-types": "^15.5.4",
26-
"react": "^15.0.0 || ^16.0.0",
27-
"react-dom": "^15.0.0 || ^16.0.0"
26+
"react": "^16.8.0",
27+
"react-dom": "^16.8.0"
2828
},
2929
"devDependencies": {
3030
"@svgr/rollup": "^2.4.1",
@@ -44,8 +44,8 @@
4444
"eslint-plugin-react": "^7.10.0",
4545
"eslint-plugin-standard": "^3.1.0",
4646
"gh-pages": "^1.2.0",
47-
"react": "^16.4.1",
48-
"react-dom": "^16.4.1",
47+
"react": "^16.8.0",
48+
"react-dom": "^16.8.0",
4949
"react-scripts": "^1.1.4",
5050
"rollup": "^0.64.1",
5151
"rollup-plugin-babel": "^3.0.7",

src/index.js

Lines changed: 59 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,60 @@
1-
import React, { Component } from 'react'
2-
import PropTypes from 'prop-types'
3-
4-
import styles from './styles.css'
5-
6-
export default class ExampleComponent extends Component {
7-
static propTypes = {
8-
text: PropTypes.string
9-
}
10-
11-
render() {
12-
const {
13-
text
14-
} = this.props
15-
16-
return (
17-
<div className={styles.test}>
18-
Example Component: {text}
19-
</div>
20-
)
21-
}
1+
import { useEffect } from 'react'
2+
3+
/**
4+
* For improve the performance, we are using requestAnimationFrame to throttle
5+
* the number of scrolling events we process to be only 1 per frame.
6+
* @param {Array<Object>} scrollContainerRefList - List of React Refs
7+
*/
8+
export default function useSyncScroll(scrollContainerRefList) {
9+
useEffect(() => {
10+
// Map the list of React ref to the actual list of node.
11+
const containerList = scrollContainerRefList.map(ref => ref.current)
12+
let requestAnimId
13+
14+
function onScroll(e) {
15+
const scrolledContainer = e.target
16+
17+
containerList.forEach((container) => {
18+
// Update all containers except the one currently
19+
// scrolling.
20+
if (container && container !== scrolledContainer) {
21+
container.scrollLeft = scrolledContainer.scrollLeft
22+
}
23+
})
24+
// Stop listening to scroll events until next frame
25+
removeScrollListeners()
26+
window.requestAnimationFrame(() => {
27+
// Start listening again to scroll events on the
28+
// next frame.
29+
addScrollListeners()
30+
})
31+
}
32+
33+
function removeScrollListeners() {
34+
if (requestAnimId) {
35+
window.cancelAnimationFrame(requestAnimId)
36+
}
37+
containerList.forEach((scrollContainer) => {
38+
if (scrollContainer) {
39+
scrollContainer.removeEventListener('scroll', onScroll)
40+
}
41+
})
42+
}
43+
44+
function addScrollListeners() {
45+
requestAnimId = window.requestAnimationFrame(() => {
46+
containerList.forEach((scrollContainer) => {
47+
if (scrollContainer) {
48+
scrollContainer.addEventListener('scroll', onScroll)
49+
}
50+
})
51+
52+
requestAnimId = null
53+
})
54+
}
55+
56+
addScrollListeners()
57+
58+
return removeScrollListeners
59+
}, [scrollContainerRefList])
2260
}

src/styles.css

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

src/test.js

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

0 commit comments

Comments
 (0)