I use "Scrollytelling" in my React application and need to change an svg dynamically according to the current scrollprogress of a section. For example like this:
useEffect(() => {
if(scrollProgress > 0.5 && scrollProgress < 0.7) foo(); // Called at each change of scrollProgress
if(scrollProgress > 0.7 && scrollProgress < 0.9) bar(); // Called at each change of scrollProgress
// etc.
}, [scrollProgress]);
But I do not want to call these functions at every change of scrollProgress which changes very frequently, I only want to call it once (and not at the first render of the element then I would use an empty dependeny-Array). Surely this has to be something that happens all the time. I cannot imagine to make a state variable "hasCalled" for each function I want to call in such a scenario and change it accordingly.
Heres an example of where I want to draw an arrow only if the scrollProgress reaches a certain threshold (problem is, it keeps calling the drawArrow() function as scrollProgress keeps on changing)
What is the proper way to handle something like this?
By initialize a ref
with start
, end
, action
( which is the function will get executed ), called
( flag to determine if it get called or not ), then check the scrollProgress
is in the range and didn't get called, then execute the action
, and then mark the called
to be true
.
function Component({ scrollProgress }) {
const actions = useRef([
{ start: 0.5, end: 0.7, action: action1, called: false },
{ start: 0.7, end: 0.9, action: action2, called: false },
// Add more actions if needed
]).current;
useEffect(() => {
actions.forEach((item) => {
if (scrollProgress > item.start && scrollProgress < item.end && !item.called) {
item.action();
item.called = true; // Mark as called
} else if (scrollProgress <= item.start || scrollProgress >= item.end) {
item.called = false; // Reset if out of range
}
});
}, [scrollProgress, actions]);
return <div>Current Scroll: {scrollProgress}</div>;
}