3

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".

Apple

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%;
}
sergdenisov
  • 8,327
  • 9
  • 48
  • 63
Mathis
  • 67
  • 1
  • 8
  • Does this answer your question? [Change Image on Scroll Position](https://stackoverflow.com/questions/24239897/change-image-on-scroll-position) – sergdenisov Apr 04 '21 at 13:36

3 Answers3

1

There are plenty of solutions for this but basically you can set in this way. Wheel event listener turns either positive or negative value so you should create an algorithm if you want to impelement different designs.

import React, { useState } from "react";
export default function App() {
  const [bgImage, handleImage] = useState(
    "https://media.wired.com/photos/5e9f56f143e5800008514457/1:1/w_1277,h_1277,c_limit/Gear-Feature-Apple_new-iphone-se-white_04152020.jpg"
  );
  window.addEventListener("wheel", (e) => {
    if (e.deltaY > 0) {
      handleImage(
        "https://media.wired.com/photos/5bcea2642eea7906bba84c67/master/w_2560%2Cc_limit/iphonexr.jpg"
      );
    } else {
      handleImage(
        "https://media.wired.com/photos/5e9f56f143e5800008514457/1:1/w_1277,h_1277,c_limit/Gear-Feature-Apple_new-iphone-se-white_04152020.jpg"
      );
    }
  });

  return (
    <div className="App">
      <img
        style={{ width: "400px", height: "300px" }}
        id="myimage"
        src={bgImage}
        alt=""
      />
    </div>
  );
}
   

And as a result you can use bgImage state in your image src.

This is a codesandbox example https://codesandbox.io/s/pensive-vaughan-cfc63?fontsize=14&hidenavigation=1&theme=dark

Evren
  • 4,147
  • 1
  • 9
  • 16
  • Do you have a example to implement this because I don't understand how to use handleColor ? – Mathis Apr 04 '21 at 14:11
  • Well it works but the image is moving down when I scroll. I want something like on my example.When the user hit the bottom of the initial image, we switch the picture. Take a look on the link in the first message :) – Mathis Apr 04 '21 at 19:42
  • I have edited my answer and new code is here https://codesandbox.io/s/pensive-vaughan-cfc63?fontsize=14&hidenavigation=1&theme=dark :) – Evren Apr 04 '21 at 21:10
1

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:

CodeSandbox

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;
}
sergdenisov
  • 8,327
  • 9
  • 48
  • 63
0

You can try useEffect and useRef.

useEffect is sideload functions, and useRef is for real dom referances.

import React, { useRef, useState, useEffect } from 'react';

import logoOrdiW from "../../images/mathis_computer_white.jpg";
import logoOrdiB from "../../images/mathis_computer_black.jpg";

import './BackgroundDiscover.css';

const BackgroundDiscover = () => {
  const img = useRef();
  const [src, setSrc] = useState(logoOrdiW);
  const switchBrackground = () => {
    setSrc(logoOrdiB);
  }
  useEffect(() => {
    img.current.onscroll = switchBrackground;
  }, []);

  return (
    <div className="container-discover">
      <div className='container-logo-white'>
        <img src={src} alt="logo ordinateur mathis blanc" ref={img} />
      </div>
    </div>
  );
};

export default BackgroundDiscover;
Aykhan Huseyn
  • 94
  • 1
  • 7