I try to switch from an image to another one when scrolling with React but I don't know how to do this... maybe with React hook. I know it's possible with jQuery but I don't want to use it.
Example here: https://www.apple.com/iphone-12/, look at the "Five fresh finishes".
import React, {useState} from 'react';
import './BackgroundDiscover.css';
import logoOrdiW from "../../images/mathis_computer_white.jpg";
import logoOrdiB from "../../images/mathis_computer_black.jpg";
const BackgroundDiscover = () => {
const [imageSrc, SetSrc] = useState(logoOrdiW);
const switchBrackground = () => {
SetSrc(logoOrdiB);
}
return (
<>
<div className="container-discover">
<div className='container-logo-white'>
<img src={imageSrc} alt="logo ordinateur mathis blanc" onScroll={switchBrackground}/>
</div>
</div>
</>
);
};
export default BackgroundDiscover;
.container-discover {
display: flex;
flex-direction: column;
}
.container-logo-white img {
width: 100%;
}
.container-logo-black img {
width: 100%;
}
You don't need jQuery or something like this. You could subscribe to scroll
event in useEffect()
hook with addEventListener
and check scrollTop
of a scrolling container.
If you want to do the same effect as the Apple website has, you could add some magic with position: sticky
, height
in vh
units and checking window.innerHeight
.
Note that this code is simplified, not optimized, and only needed to understand the idea:
index.js
:
import { useLayoutEffect, useState } from "react";
import { render } from "react-dom";
import classnames from "classnames";
import "./index.css";
const images = [0, 1, 2, 3, 4];
const App = () => {
const [visibleImagesMap, setVisibleImagesMap] = useState(
images.reduce((map, image) => {
map[image] = false;
return map;
}, {})
);
useLayoutEffect(() => {
const handleScroll = () => {
const scrollTop = document.documentElement.scrollTop;
const viewportHeight = window.innerHeight;
const newVisibleImagesMap = images.reduce((map, image) => {
map[image] = scrollTop >= image * viewportHeight;
return map;
}, {});
setVisibleImagesMap(newVisibleImagesMap);
};
window.addEventListener("scroll", handleScroll);
handleScroll();
return () => window.removeEventListener("scroll", handleScroll);
}, []);
return (
<div className="app">
<div className="sticky">
<div className="frame">
{images.map((image) => (
<div
className={classnames("image", `image_${image}`, {
image_visible: visibleImagesMap[image]
})}
key={image}
/>
))}
</div>
</div>
</div>
);
};
render(<App />, document.getElementById("root"));
index.css
:
body {
margin: 0;
}
.app {
height: 500vh;
}
.sticky {
position: sticky;
top: 0;
height: 100vh;
}
.frame {
z-index: 1;
position: relative;
height: 100%;
width: 100%;
}
.image {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0;
background-repeat: no-repeat;
background-size: cover;
}
.image_0 {
z-index: 0;
background-image: url("./images/0.jpeg");
}
.image_1 {
z-index: 1;
background-image: url("./images/1.jpeg");
}
.image_2 {
z-index: 2;
background-image: url("./images/2.jpeg");
}
.image_3 {
z-index: 3;
background-image: url("./images/3.jpeg");
}
.image_4 {
z-index: 4;
background-image: url("./images/4.jpeg");
}
.image_visible {
opacity: 1;
}