Skip to content

Commit 489d47b

Browse files
authored
Merge pull request #22 from onderonur/observer
Major Update, Using IntersectionObserver Under the Hood, New Examples for Different List Types
2 parents 761d17d + a6bd923 commit 489d47b

22 files changed

+3965
-4061
lines changed

.eslintrc.js

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
module.exports = {
2+
env: {
3+
browser: true,
4+
es6: true,
5+
},
6+
extends: ['react-app', 'plugin:react/recommended', 'airbnb', 'prettier'],
7+
parser: '@typescript-eslint/parser',
8+
parserOptions: {
9+
ecmaFeatures: {
10+
jsx: true,
11+
},
12+
ecmaVersion: 12,
13+
sourceType: 'module',
14+
},
15+
plugins: ['react', '@typescript-eslint', 'prettier'],
16+
settings: {
17+
'import/resolver': {
18+
node: {
19+
extensions: ['.js', '.jsx', '.ts', '.tsx'],
20+
},
21+
},
22+
},
23+
rules: {
24+
'prettier/prettier': 'warn',
25+
'no-shadow': 'warn',
26+
'no-unused-vars': 'off',
27+
"prefer-destructuring": "warn",
28+
'@typescript-eslint/no-unused-vars': 'warn',
29+
// For optional chaining to not create linting errors
30+
'no-unused-expressions': 'off',
31+
"no-plusplus": "off",
32+
"operator-assignment": "warn",
33+
"object-shorthand": "warn",
34+
'arrow-body-style': 'off',
35+
"radix": "off",
36+
'import/extensions': 'off',
37+
'import/no-extraneous-dependencies': 'off',
38+
'import/order': 'off',
39+
'import/newline-after-import': 'warn',
40+
'no-use-before-define': 'off',
41+
"@typescript-eslint/no-explicit-any": "warn",
42+
'@typescript-eslint/no-use-before-define': 'warn',
43+
'react/jsx-curly-newline': 'off',
44+
'react/jsx-tag-spacing': 'warn',
45+
'react/button-has-type': 'warn',
46+
"react/jsx-fragments": "warn",
47+
'react/jsx-filename-extension': [
48+
'warn',
49+
{ extensions: ['.js', '.jsx', '.ts', '.tsx'] },
50+
],
51+
},
52+
};

.eslintrc.json

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

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Change Log
2+
3+
Plesae check [Releases](https://github.com/onderonur/react-infinite-scroll-hook/releases) page for migration instructions.

example/InfiniteList.tsx

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

example/components/List.tsx

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import * as React from 'react';
2+
import styled, { keyframes } from 'styled-components';
3+
4+
interface ListProps {
5+
direction?: 'vertical' | 'horizontal';
6+
}
7+
8+
export const List = styled.ul<ListProps>`
9+
display: ${({ direction }) =>
10+
direction === 'horizontal' ? 'flex' : 'block'};
11+
list-style: none;
12+
font-size: 16px;
13+
margin: 0;
14+
padding: 6px;
15+
`;
16+
17+
export const ListItem = styled.li`
18+
background-color: #fafafa;
19+
border: 1px solid #99b4c0;
20+
padding: 8px;
21+
margin: 4px;
22+
`;
23+
24+
const gradientAnimation = keyframes`
25+
0% {
26+
background-position: 0% 50%;
27+
}
28+
50% {
29+
background-position: 100% 50%;
30+
}
31+
100% {
32+
background-position: 0% 50%;
33+
}
34+
`;
35+
36+
const LoadingRoot = styled.div`
37+
animation: ${gradientAnimation} 2s linear infinite;
38+
background: linear-gradient(45deg, #298fee, #11c958, #a120bb, #d6612a);
39+
background-size: 600% 600%;
40+
color: #fff;
41+
padding: 8px;
42+
`;
43+
44+
export function Loading() {
45+
return <LoadingRoot>Loading...</LoadingRoot>;
46+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import * as React from 'react';
2+
import styled from 'styled-components';
3+
import useInfiniteScroll from '../../src';
4+
import { useLoadItems } from '../utils';
5+
import { List, ListItem, Loading } from '../components/List';
6+
7+
const ListContainer = styled.div`
8+
background-color: #fafafa;
9+
`;
10+
11+
const Footer = styled.div`
12+
height: 600px;
13+
background-color: #dcdcdc;
14+
`;
15+
16+
function SimpleInfiniteList() {
17+
const { loading, items, hasNextPage, error, loadMore } = useLoadItems();
18+
19+
const [infiniteRef] = useInfiniteScroll({
20+
loading,
21+
hasNextPage,
22+
onLoadMore: loadMore,
23+
// When there is an error, we stop infinite loading.
24+
// It can be reactivated by setting "error" state as undefined.
25+
disabled: !!error,
26+
rootMargin: '0px 0px 400px 0px',
27+
});
28+
29+
return (
30+
<>
31+
<ListContainer>
32+
<List>
33+
{items.map((item) => (
34+
<ListItem key={item.key}>{item.value}</ListItem>
35+
))}
36+
{/*
37+
As long as we have a "next page", we show "Loading" right under the list.
38+
When it becomes visible on the screen, or it becomes near, it triggers 'onLoadMore'.
39+
This is our "sentry".
40+
We can also use another "sentry" which is separated from the "Loading" component like:
41+
<div ref={infiniteRef} />
42+
{loading && <ListItem>Loading...</ListItem>}
43+
and leave "Loading" without this ref.
44+
*/}
45+
{hasNextPage && (
46+
<ListItem ref={infiniteRef}>
47+
<Loading />
48+
</ListItem>
49+
)}
50+
</List>
51+
</ListContainer>
52+
<Footer>Footer</Footer>
53+
</>
54+
);
55+
}
56+
57+
export default SimpleInfiniteList;
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import * as React from 'react';
2+
import styled from 'styled-components';
3+
import useInfiniteScroll from '../../src';
4+
import { useLoadItems } from '../utils';
5+
import { List, ListItem, Loading } from '../components/List';
6+
7+
const ListContainer = styled.div`
8+
max-width: 600px;
9+
overflow: auto;
10+
background-color: #fafafa;
11+
`;
12+
13+
function InfiniteListWithHorizontalScroll() {
14+
const { loading, items, hasNextPage, error, loadMore } = useLoadItems();
15+
16+
const [infiniteRef, { rootRef }] = useInfiniteScroll({
17+
loading,
18+
hasNextPage,
19+
onLoadMore: loadMore,
20+
disabled: !!error,
21+
rootMargin: '0px 400px 0px 0px',
22+
});
23+
24+
return (
25+
<>
26+
<ListContainer ref={rootRef}>
27+
<List direction="horizontal">
28+
{items.map((item) => (
29+
<ListItem key={item.key}>{item.value}</ListItem>
30+
))}
31+
{hasNextPage && (
32+
<ListItem ref={infiniteRef}>
33+
<Loading />
34+
</ListItem>
35+
)}
36+
</List>
37+
</ListContainer>
38+
</>
39+
);
40+
}
41+
42+
export default InfiniteListWithHorizontalScroll;
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import * as React from 'react';
2+
import styled from 'styled-components';
3+
import useInfiniteScroll from '../../src';
4+
import { useLoadItems } from '../utils';
5+
import { List, ListItem, Loading } from '../components/List';
6+
7+
const ListContainer = styled.div`
8+
max-width: 600px;
9+
overflow: auto;
10+
background-color: #fafafa;
11+
`;
12+
13+
function InfiniteListWithReverseHozirontalScroll() {
14+
const { loading, items, hasNextPage, error, loadMore } = useLoadItems();
15+
16+
const [infiniteRef, { rootRef }] = useInfiniteScroll({
17+
loading,
18+
hasNextPage,
19+
onLoadMore: loadMore,
20+
disabled: !!error,
21+
rootMargin: '0px 0px 0px 400px',
22+
});
23+
24+
const scrollableRootRef = React.useRef<HTMLDivElement | null>(null);
25+
const lastScrollDistanceToRightRef = React.useRef<number>();
26+
27+
const reversedItems = React.useMemo(() => [...items].reverse(), [items]);
28+
29+
// We keep the scroll position when new items are added etc.
30+
React.useEffect(() => {
31+
const scrollableRoot = scrollableRootRef.current;
32+
const lastScrollDistanceToRight = lastScrollDistanceToRightRef.current ?? 0;
33+
if (scrollableRoot) {
34+
scrollableRoot.scrollLeft =
35+
scrollableRoot.scrollWidth - lastScrollDistanceToRight;
36+
}
37+
}, [reversedItems, rootRef]);
38+
39+
const rootRefSetter = React.useCallback(
40+
(node: HTMLDivElement) => {
41+
rootRef(node);
42+
scrollableRootRef.current = node;
43+
},
44+
[rootRef],
45+
);
46+
47+
const handleRootScroll = React.useCallback(() => {
48+
const rootNode = scrollableRootRef.current;
49+
if (rootNode) {
50+
const scrollDistanceToRight = rootNode.scrollWidth - rootNode.scrollLeft;
51+
lastScrollDistanceToRightRef.current = scrollDistanceToRight;
52+
}
53+
}, []);
54+
55+
return (
56+
<>
57+
<ListContainer ref={rootRefSetter} onScroll={handleRootScroll}>
58+
<List direction="horizontal">
59+
{hasNextPage && (
60+
<ListItem ref={infiniteRef}>
61+
<Loading />
62+
</ListItem>
63+
)}
64+
{reversedItems.map((item) => (
65+
<ListItem key={item.key}>{item.value}</ListItem>
66+
))}
67+
</List>
68+
</ListContainer>
69+
</>
70+
);
71+
}
72+
73+
export default InfiniteListWithReverseHozirontalScroll;

0 commit comments

Comments
 (0)