Skip to content

Commit ea12661

Browse files
committed
Make Horizontal element use less layer memory
1 parent bec70c5 commit ea12661

File tree

7 files changed

+65
-45
lines changed

7 files changed

+65
-45
lines changed

README.md

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,23 @@
11
# React ScrollyTelling
22

3-
> Create scrolly-telling animations in React with ease.
3+
Create scrolly-telling animations in React with ease.
4+
5+
[![Release](https://badgen.net/npm/v/react-scrolly-telling)](https://www.npmjs.com/package/react-scrolly-telling)
6+
[![Types](https://badgen.net/npm/types/react-scrolly-telling)](https://www.npmjs.com/package/react-scrolly-telling)
7+
[![License](https://badgen.net/github/license/guptasiddhant/react-scrolly-telling)](https://github.com/GuptaSiddhant/react-scrolly-telling/blob/main/LICENSE)
8+
[![Total downloads](https://badgen.net/npm/dt/react-scrolly-telling)](https://www.npmjs.com/package/react-scrolly-telling)
9+
[![Releases](https://badgen.net/github/releases/guptasiddhant/react-scrolly-telling)](https://github.com/GuptaSiddhant/react-scrolly-telling/releases)
10+
11+
[![Minified GZip](https://badgen.net/bundlephobia/minzip/react-scrolly-telling)](https://bundlephobia.com/package/react-scrolly-telling)
12+
[![Dependency count](https://badgen.net/bundlephobia/dependency-count/react-scrolly-telling)](https://bundlephobia.com/package/react-scrolly-telling)
13+
[![Tree shaking](https://badgen.net/bundlephobia/tree-shaking/react-scrolly-telling)](https://bundlephobia.com/package/react-scrolly-telling)
414

515
`react-scrolly-telling` is a helper library to track the position of an element on the screen with respect to the viewport (or other parent element). It is optimised to work well with React, SSR, and Suspense.
616

7-
[GitHub](https://www.github.com/GuptaSiddhant/react-scrolly-telling) | [NPM](https://www.npmjs.com/package/react-scrolly-telling) | [Docs/Demo](https:///react-scrolly-telling.vercel.app/)
17+
- **[Docs/Demo - Storybook](https:///react-scrolly-telling.vercel.app/)**
18+
- [GitHub](https://www.github.com/GuptaSiddhant/react-scrolly-telling)
19+
- [NPM](https://www.npmjs.com/package/react-scrolly-telling)
20+
- [Bundlephobia](https://bundlephobia.com/package/react-scrolly-telling)
821

922
## Installation
1023

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "react-scrolly-telling",
3-
"version": "0.1.3",
3+
"version": "0.1.4",
44
"description": "Create scrolly-telling animations in React with ease.",
55
"type": "module",
66
"keywords": [

src/components/ScrollyHorizontalElement.tsx

Lines changed: 22 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
import { forwardRef, useRef } from "react";
1+
import { forwardRef, useCallback, useRef } from "react";
22

33
import interpolate from "../interpolate.js";
4-
import { mergeRefs, useStableLayoutEffect } from "../utils/react-helpers.js";
4+
import useAnimationFrame from "../utils/animation-frame.js";
5+
import { mergeRefs, type Styles } from "../utils/react-helpers.js";
56
import { ScrollyElementContext } from "../utils/scrolly-context.js";
6-
import useScrolly from "../utils/use-scrolly.js";
7+
import useScrolly, { ScrollyValues } from "../utils/use-scrolly.js";
78

89
export interface ScrollyHorizontalElementProps {
910
as?: React.ElementType;
@@ -26,6 +27,7 @@ const styles = {
2627
position: "sticky",
2728
top: 0,
2829
height: "100vh",
30+
width: "100vw",
2931
display: "inline-block",
3032
overflow: "hidden",
3133
},
@@ -38,7 +40,7 @@ const styles = {
3840
willChange: "transform",
3941
pointerEvents: "auto",
4042
},
41-
} satisfies Record<string, React.CSSProperties>;
43+
} satisfies Styles;
4244

4345
const ScrollyHorizontalElement = (
4446
props: ScrollyHorizontalElementProps,
@@ -86,48 +88,28 @@ const ScrollyHorizontalElement = (
8688

8789
export default forwardRef(ScrollyHorizontalElement);
8890

89-
const CSS_PROPERTY_OVERFLOW_X = "overflow-x";
90-
9191
function useScrollyHorizontalElementLayout(
9292
containerRef: React.RefObject<HTMLDivElement>,
9393
contentRef: React.RefObject<HTMLDivElement>
94-
) {
95-
const timeRef = useRef(0);
94+
): ScrollyValues {
9695
const scrollyValues = useScrolly(containerRef, {
9796
precision: 3,
9897
});
9998
const { windowWidth, windowHeight, scrollRatio } = scrollyValues;
10099

101-
// Make sure the body doesn't scroll horizontally itself
102-
useStableLayoutEffect(() => {
103-
const previousOverflowX = document.body.style.getPropertyValue(
104-
CSS_PROPERTY_OVERFLOW_X
105-
);
106-
document.body.style.setProperty(CSS_PROPERTY_OVERFLOW_X, "hidden");
107-
108-
return () =>
109-
document.body.style.setProperty(
110-
CSS_PROPERTY_OVERFLOW_X,
111-
previousOverflowX
112-
);
113-
}, []);
114-
115-
useStableLayoutEffect(() => {
116-
const contentScrollWidth = contentRef.current?.scrollWidth || 0;
117-
const scrollDistance = Math.max(contentScrollWidth - windowWidth, 0);
118-
119-
// Make container taller to accommodate scroll distance
120-
const containerHeight = windowHeight + scrollDistance;
121-
containerRef.current?.style.setProperty("height", `${containerHeight}px`);
100+
const handleAnimationFrame = useCallback(
101+
(_: number, delta: number) => {
102+
const contentScrollWidth = contentRef.current?.scrollWidth || 0;
103+
const scrollDistance = Math.max(contentScrollWidth - windowWidth, 0);
122104

123-
const translateValue = interpolate(scrollRatio, {
124-
targetFrom: 0,
125-
targetTo: scrollDistance,
126-
}).toFixed(0);
105+
// Make container taller to accommodate scroll distance
106+
const containerHeight = windowHeight + scrollDistance;
107+
containerRef.current?.style.setProperty("height", `${containerHeight}px`);
127108

128-
const frame = window.requestAnimationFrame((time) => {
129-
const delta = time - timeRef.current;
130-
timeRef.current = time;
109+
const translateValue = interpolate(scrollRatio, {
110+
targetFrom: 0,
111+
targetTo: scrollDistance,
112+
}).toFixed(0);
131113

132114
contentRef.current?.animate(
133115
{ transform: `translateX(-${translateValue}px)` },
@@ -138,10 +120,11 @@ function useScrollyHorizontalElementLayout(
138120
playbackRate: 1 + delta / 100,
139121
}
140122
);
141-
});
123+
},
124+
[containerRef, contentRef, scrollRatio, windowHeight, windowWidth]
125+
);
142126

143-
return () => window.cancelAnimationFrame(frame);
144-
}, [windowHeight, windowWidth, scrollRatio, contentRef, containerRef]);
127+
useAnimationFrame(handleAnimationFrame);
145128

146129
return scrollyValues;
147130
}

src/components/ScrollyVerticalElement.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { forwardRef, useRef } from "react";
33
import useScrolly from "../utils/use-scrolly.js";
44
import { ScrollyElementContext } from "../utils/scrolly-context.js";
55
import type { ScrollyOptions } from "../utils/types.js";
6-
import { mergeRefs } from "../utils/react-helpers.js";
6+
import { mergeRefs, type Styles } from "../utils/react-helpers.js";
77

88
export interface ScrollyVerticalElementProps
99
extends Omit<ScrollyOptions, "disabled"> {
@@ -21,7 +21,7 @@ const styles = {
2121
position: "relative",
2222
width: "100%",
2323
},
24-
} satisfies Record<string, React.CSSProperties>;
24+
} satisfies Styles;
2525

2626
const ScrollyVerticalElement = forwardRef<
2727
HTMLDivElement,

src/components/Video.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { useEffect, useRef } from "react";
22

33
import interpolate from "../interpolate.js";
4+
import { type Styles } from "../utils/react-helpers.js";
45
import { useScrollyElementContext } from "../utils/scrolly-context.js";
56

67
const styles = {
@@ -12,7 +13,7 @@ const styles = {
1213
height: "100vh",
1314
objectFit: "cover",
1415
},
15-
} satisfies Record<string, React.CSSProperties>;
16+
} satisfies Styles;
1617

1718
export interface VideoProps {
1819
src: string;

src/utils/animation-frame.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { useRef } from "react";
2+
import { useStableLayoutEffect } from "./react-helpers.js";
3+
4+
export default function useAnimationFrame(
5+
callback: (time: number, delta: number) => void
6+
): void {
7+
const timeRef = useRef(0);
8+
9+
useStableLayoutEffect(() => {
10+
const animationFrame = window.requestAnimationFrame((time) => {
11+
const delta = time - timeRef.current;
12+
timeRef.current = time;
13+
14+
callback(time, delta);
15+
});
16+
17+
return () => {
18+
window.cancelAnimationFrame(animationFrame);
19+
};
20+
}, [callback, cancelAnimationFrame]);
21+
}

src/utils/react-helpers.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,5 @@ export function mergeRefs<T>(...refs: React.Ref<T>[]) {
1414

1515
export const useStableLayoutEffect =
1616
typeof window === "undefined" ? useEffect : useLayoutEffect;
17+
18+
export type Styles = Record<string, React.CSSProperties>;

0 commit comments

Comments
 (0)