简体   繁体   中英

How to make a scroll event in react?

I'm trying to make an animation that draws an SVG as you scroll down the page.

I've managed to get it to work in vanilla js but having issues with react. Each time I refresh the page it crashes.

I think it's due to the browser struggling to keep up to date with the most recent path length. as the error I'm getting is (path.getTotalLength is not a function) on each refresh.

I'm also unsure how to link a react event listener to my HTML.

Any advice about tackling this would be great

Thanks

import { useRef } from "react";

function About() {
  const pathRef = useRef();

  let path = pathRef;
  let pathLength = path.getTotalLength();

  path.style.strokeDasharray = pathLength + " " + pathLength;

  path.style.strokeDashoffset = pathLength;

  window.addEventListener("scroll", () => {
    let scrollPercentage =
      (document.documentElement.scrollTop + document.body.scrollTop) /
      (document.documentElement.scrollHeight -
        document.documentElement.clientHeight);
    let drawLength = pathLength * scrollPercentage;
    path.style.strokeDashoffset = pathLength - drawLength;
  });

  return (
    <div className="about">
      <div className="about__container">
        <svg
          viewBox="0 0 1043 1831"
          fill="none"
          preserveAspectRatio="xMidYMax meet"
        >
          <path
            ref={path}
            d="M1184.5 3C503.5 3 763 316 595.5 431.5V376.5L645.5 423.5C664.167 436.167 708 446.5 736 426C764.312 405.271 763 402.5 763 402.5C754 390.667 730.4 368 690 368C649.6 368 620.5 409.624 612 418.276L609.5 609H995.5L1.5 1051.5H587.5C590 1059.67 603.3 1076 636.5 1076C638.5 1076 638.667 1074.67 638.5 1074C638.833 1065.33 640.5 1048.2 644.5 1049C649.5 1050 576 1037.5 603 980.5L609.5 971C607.833 961 605.5 941.1 609.5 941.5C613.5 941.9 631.167 950.333 639.5 954.5C651.9 951.3 679.333 952.167 691.5 953C699.667 948.167 716.2 939.1 717 941.5C718 944.5 721 967.5 719 972.5C726 986.5 745.5 1041 681.5 1050C684.5 1049 689.4 1057.8 689 1069L681.5 1440.5C677.5 1793.5 820 1654 1082.5 1654"
            stroke="#0000FF"
            stroke-width="6"
          />
          ;
        </svg>
        <div className="about__landing"></div>
      </div>
    </div>
  );
}

export default About;

With hooks you can implement it this way:

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

function MyApp () {

    const [offset, setOffset] = useState(0);

    useEffect(() => {
        const onScroll = () => setOffset(window.pageYOffset);
        // clean up code
        window.removeEventListener('scroll', onScroll);
        window.addEventListener('scroll', onScroll, { passive: true });
        return () => window.removeEventListener('scroll', onScroll);
    }, []);

    console.log(offset); 
};

The useRef hook doesn't have a reference to the <path /> element until after the first render.

Use the useRef hook in combination with a useEffect hook to set the path length and add the event listener whenever the first render happens.

The actual reference to the element is stored in the current property of the useRef hook value.

import { useRef, useEffect } from "react";

function About() {
  const pathRef = useRef();

  useEffect(() => {
    let pathLength = path.current.getTotalLength();

    path.current.style.strokeDasharray = pathLength + " " + pathLength;
    path.current.style.strokeDashoffset = pathLength;

    window.addEventListener("scroll", () => {
      let scrollPercentage =
        (document.documentElement.scrollTop + document.body.scrollTop) /
        (document.documentElement.scrollHeight -
          document.documentElement.clientHeight);
      let drawLength = pathLength * scrollPercentage;
      path.currnet.style.strokeDashoffset = pathLength - drawLength;
    });
  }, []);

  return (
    <div className="about">
      <div className="about__container">
        <svg
          viewBox="0 0 1043 1831"
          fill="none"
          preserveAspectRatio="xMidYMax meet"
        >
          <path
            ref={path}
            d="M1184.5 3C503.5 3 763 316 595.5 431.5V376.5L645.5 423.5C664.167 436.167 708 446.5 736 426C764.312 405.271 763 402.5 763 402.5C754 390.667 730.4 368 690 368C649.6 368 620.5 409.624 612 418.276L609.5 609H995.5L1.5 1051.5H587.5C590 1059.67 603.3 1076 636.5 1076C638.5 1076 638.667 1074.67 638.5 1074C638.833 1065.33 640.5 1048.2 644.5 1049C649.5 1050 576 1037.5 603 980.5L609.5 971C607.833 961 605.5 941.1 609.5 941.5C613.5 941.9 631.167 950.333 639.5 954.5C651.9 951.3 679.333 952.167 691.5 953C699.667 948.167 716.2 939.1 717 941.5C718 944.5 721 967.5 719 972.5C726 986.5 745.5 1041 681.5 1050C684.5 1049 689.4 1057.8 689 1069L681.5 1440.5C677.5 1793.5 820 1654 1082.5 1654"
            stroke="#0000FF"
            stroke-width="6"
          />
          ;
        </svg>
        <div className="about__landing"></div>
      </div>
    </div>
  );
}

export default About;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM