'Keep elements visible after first scroll using react-visibility-sensor
Using react-visibility-sensor I've created a higher component to animate the sections of my project on scroll.
I'm having problems trying to make it work only on the first scroll. At the moment the sections appear and disappear.
Any help would be really appreciated. Cheers!
import VisibilitySensor from 'react-visibility-sensor';
export const SlideUp = ({ children }) => {
const [isVisible, setVisibility] = useState(false);
const onChange = visiblity => {
setVisibility(visiblity);
};
return (
<VisibilitySensor
partialVisibility
offset={{ top: 200 }}
onChange={onChange}
>
<div
style={{
transition: `opacity ${0.5}s ease, transform ${0.5}s ease`,
opacity: isVisible ? 1 : 0,
transform: isVisible ? `translateY(${0}px)` : `translateY(${20}px)`,
}}
>
{children}
</div>
</VisibilitySensor>
);
};```
- use example:
<SlideUp>
<Section />
</SlideUp>
Solution 1:[1]
My solution was to mix React Pose with React Visibility.
The visibility triggers the animation in React Pose which happens only once. The animation relies on Pose and not on visibility.
import VisibilitySensor from 'react-visibility-sensor';
import posed from 'react-pose';
const PoseDiv = posed.div({
enter: {
y: 0,
opacity: 1,
transition: {
duration: 300,
ease: 'easeIn',
},
},
exit: { y: 20, opacity: 0 },
});
export const SlideUp = ({ children }) => {
const [isVisible, setVisibility] = useState(false);
const [entered, setEntered] = useState(false);
const onChange = visiblity => {
setVisibility(visiblity);
};
useEffect(() => {
if (isVisible) {
setEntered(true);
}
}, [isVisible]);
return (
<>
<VisibilitySensor
partialVisibility
offset={{ top: 100 }}
onChange={onChange}
>
<PoseDiv pose={entered ? 'enter' : 'exit'}>{children}</PoseDiv>
</VisibilitySensor>
</>
);
};
I hope it helps somebody else. Cheers!
PS: this solution needs to be updated due to the fact that React Pose is now deprecated.
Solution 2:[2]
import VisibilitySensor from 'react-visibility-sensor';
export const SlideUp = ({ children }) => {
const [isVisible, setVisibility] = useState(false);
const onChange = visiblity => {
setVisibility(visiblity);
};
return (
<VisibilitySensor
partialVisibility
offset={{ top: 200 }}
onChange={onChange}
>
<div
className={`example ${isVisible ? 'visible' : ''}`}
>
{children}
</div>
</VisibilitySensor>
);
};
CSS
.example{
...
opacity: 0;
transform: translateY(20px);
transition: opacity 0.5s ease, transform 0.5s ease;
}
.example.visible{
opacity: 1;
transform: translateY(0px);
}
Try to use className
Solution 3:[3]
I think you are toggling the visibility state, to keep the ui visible once displayed do not change the state to invisible
just change
const onChange = visiblity => {
setVisibility(visiblity);
};
to
const onChange = visiblity => {
if(visiblity){
setVisibility(visiblity);
}
};
Solution 4:[4]
This is the solution that I have been using. Just use hasBeenVisible render prop instead of isVisible.
import React, { useState } from "react";
import VisibilitySensor from "react-visibility-sensor";
/**
* VisibilitySensor does not implement some kind of funcionality to track first time
* visibility. This component extends VisibilitySensor compoment to provide this
* feature. Just use `hasBeenVisible` render prop instead of `isVisible`.
*
* https://github.com/joshwnj/react-visibility-sensor/issues/117#issuecomment-686365798
*/
const AppearSensor = ({
onChange,
children,
...rest
}) => {
const [hasBeenVisible, setHasBeenVisible] = useState(false);
return (
<VisibilitySensor {...rest} onChange={(isVisible) => {
if (isVisible) setHasBeenVisible(true)
if (onChange) onChange(isVisible)
}}>
{
({
isVisible,
...restRenderProps
}) => {
return children({ isVisible, ...restRenderProps, hasBeenVisible })
}
}
</VisibilitySensor>
);
};
AppearSensor.propTypes = VisibilitySensor.propTypes
AppearSensor.defaultProps = VisibilitySensor.defaultProps
export default AppearSensor;
Solution 5:[5]
If you want the div to fade in one time then remain on the screen.
Change this
const onChange = visiblity => {
setVisibility(visiblity);
};
To this
const onChange = visiblity => {
if(visiblity)
setVisibility(true);
};
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | kyun |
| Solution 3 | 44kksharma |
| Solution 4 | |
| Solution 5 | Test1 Test2 |
