Skip to content Skip to sidebar Skip to footer

Using Useeffect To Manipulate Dom Events Not Responsive On Different Screens

Currently I'm trying to achieve the following parallax effect in React where my image is in a fixed position vertically but moves left to right along with text. I've used useEffect

Solution 1:

For a solution is refactoring your code.

  1. to place all the elements in the center and create four sections.
  2. define the center of the sections this help to find where need stop move image and move it back.
  3. in the same way need to do with text.
  4. when the window is resized all content is centered with window.resize.

Sandbox example link

functionApp() {
  const [screen, setScreen] = React.useState(false);

  const ref = React.useRef(null);

  // Reduce value if want the image to be closer to the edges// otherwise to the centerconst setImageLimitMovement = 2;

  const setTextLimitMovement = 4;
  const opacityRange = 400;
  // Speed text movementconst speed = 2; // .5React.useEffect(() => {
    window.addEventListener("resize", () => {
      if (window.innerWidth !== 0) {
        setScreen(window.innerWidth);
      }
    });
  }, []);

  React.useEffect(() => {
    const app = [...ref.current.children];
    const titles = app.filter((el) => el.matches(".titles") && el);
    const blocks = app.filter((el) => el.matches(".blocks") && el);
    const img = app.find((el) => el.matches("#passport") && el);

    // Get the center point of  blocks in an arrayconst centerPoints = blocks.map((blockEl, idx) => {
      const blockindex = idx + 1;
      const blockHeight = Math.floor(blockEl.getBoundingClientRect().height);
      const blockHalf = blockHeight / 2;
      return blockHeight * blockindex - blockHalf;
    });

    const leftMoveLimitImg = -centerPoints[0] / setImageLimitMovement;
    const rightMoveLimitImg = centerPoints[0] / setImageLimitMovement;

    const textLimit = centerPoints[0] / setTextLimitMovement;

    constchangeBackground = () => {
      const value = window.scrollY;

      titles[0].style.transform = `translateY(-${value * speed}px)`;
      // IMAGE BOUNCE// Move to <==if (centerPoints[0] > value) {
        img.style.transform = `translateX(-${
          value * (1 / setImageLimitMovement)
        }px)`;

        titles[1].style.transform = `translateX( ${
          0 + value / setTextLimitMovement
        }px)`;
        titles[1].style.opacity = value / opacityRange;
        return;
      }

      // Move to ==>if (centerPoints[1] > value) {
        const moveTextToRight =
          centerPoints[1] / setTextLimitMovement - textLimit;
        const hideText = centerPoints[0] / opacityRange;
        const checkDirection = Math.sign(
          textLimit + (textLimit - value / setTextLimitMovement)
        );

        const moveImageToRight =
          (value - centerPoints[0]) / setImageLimitMovement;
        img.style.transform = `translateX(${
          leftMoveLimitImg + moveImageToRight
        }px)`;

        if (checkDirection === -1) {
          titles[1].style.opacity = 0;
          titles[1].style.transform = `translateX(${0}px)`;

          titles[2].style.opacity =
            Math.abs(hideText - value / opacityRange) - 1;
          titles[2].style.transform = `translateX(${
            moveTextToRight - value / setTextLimitMovement
          }px)`;
          return;
        }
        if (checkDirection === 1) {
          titles[1].style.opacity = 1 + (hideText - value / opacityRange);
          titles[1].style.transform = `translateX(${
            textLimit + (textLimit - value / setTextLimitMovement)
          }px)`;

          titles[2].style.opacity = 0;
          titles[2].style.transform = `translateX(${0}px)`;
        }
        return;
      }

      // Move to <==if (centerPoints[2] > value) {
        const moveTextToLeft =
          centerPoints[2] / setTextLimitMovement - textLimit;
        const hideText = centerPoints[1] / opacityRange;
        const checkDirection = Math.sign(
          moveTextToLeft - value / setTextLimitMovement
        );

        const moveImageToLeft =
          (-value + centerPoints[1]) / setImageLimitMovement;
        img.style.transform = `translateX(${
          rightMoveLimitImg + moveImageToLeft
        }px)`;

        if (checkDirection === -1) {
          titles[2].style.opacity = 0;
          titles[2].style.transform = `translateX(${0}px)`;

          titles[3].style.opacity =
            Math.abs(hideText - value / opacityRange) - 1;
          titles[3].style.transform = `translateX(${Math.abs(
            moveTextToLeft - value / setTextLimitMovement
          )}px)`;
        }

        if (checkDirection === 1) {
          titles[2].style.opacity = 1 + (hideText - value / opacityRange);
          titles[2].style.transform = `translateX(-${
            moveTextToLeft - value / setTextLimitMovement
          }px)`;

          titles[3].style.opacity = 0;
          titles[3].style.transform = `translateX(${0}px)`;
        }
        return;
      }

      // Move to ==>if (centerPoints[3] > value) {
        const moveTextToRight =
          centerPoints[3] / setTextLimitMovement - textLimit;
        const hideText = centerPoints[2] / opacityRange;
        const checkDirection = Math.sign(
          moveTextToRight - value / setTextLimitMovement
        );

        const moveImageToRight =
          (value - centerPoints[2]) / setImageLimitMovement;
        img.style.transform = `translateX(${
          leftMoveLimitImg + moveImageToRight
        }px)`;

        if (checkDirection === -1) {
          titles[3].style.opacity = 0;
          titles[3].style.transform = `translateX(${0}px)`;
        }
        if (checkDirection === 1) {
          titles[3].style.opacity = 1 + (hideText - value / opacityRange);
          titles[3].style.transform = `translateX(${
            moveTextToRight - value / setTextLimitMovement
          }px)`;
        }
        return;
      }

      window.requestAnimationFrame(changeBackground);
    };
    window.addEventListener("scroll", changeBackground);
    return() =>window.removeEventListener("scroll", changeBackground);
  }, [screen]);

  return (
    <divclassName="App"ref={ref}><h1id="title"className="titles">
        Random Title
      </h1><sectionid="block1"className="blocks"><h4>Block 1</h4></section><figureid="passport"><imgalt="passport"src="https://cdn.britannica.com/87/122087-050-1C269E8D/Cover-passport.jpg"
        /></figure><h2id="text1"className="titles text1">
        Random Text 1
      </h2><sectionid="block2"className="blocks"><h4>Block 2</h4></section><h2id="text2"className="titles text2">
        Random Text 2
      </h2><sectionid="block3"className="blocks"><h4>Block 3</h4></section><h2id="text3"className="titles text3">
        Random Text 3
      </h2><sectionid="block4"className="blocks"><h4>Block 4</h4></section></div>
  );
}


const rootElement = document.getElementById("root");
ReactDOM.render( <
  App / > ,
  rootElement
);
* {
  padding: 0;
  margin: 0;
  box-sizing: border-box;
}
.App {
  font-family: sans-serif;
  width: 100%;
  background-color: hsl(220, 65%, 16%);
}
figure {
  width: 280px;
  height: max-content;
  position: fixed;
  inset: 0;
  margin: auto;
  z-index: 100;
}
img {
  width: 100%;
}

.blocks {
  height: 100vh;
  display: flex;
  position: relative;
  grid-column: 1 / -1;
  color: grey;
}

.titles {
  width: max-content;
  height: max-content;
  position: fixed;
  inset: 0;
  margin: auto;
  color: white;
  z-index: 99;
}

h1 {
  font-size: 3.5em;
}
h2 {
  display: flex;
  opacity: 0;
  font-size: 2.5em;
}
<scriptsrc="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script><scriptsrc="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script><divid="root"></div>

Solution 2:

You have two options.

  1. make this effect available only for the screen width size you intended
  2. calculate how many pixels you should move the passport depending on the window size of the browser.

The latter solution can make your application annoying to maintain because there will be so many devices to consider.

How to get window size

const [size, setSize] = useState({
    x: window.innerWidth,
    y: window.innerHeight
  });
  constupdateSize = () =>
    setSize({
      x: window.innerWidth,
      y: window.innerHeight
    });
  useEffect(() => (window.onresize = updateSize), []);

Post a Comment for "Using Useeffect To Manipulate Dom Events Not Responsive On Different Screens"