Cannot read property ‘style’ of undefined in useEffect

Currently I’m trying to change the layout of my webpage according to the width of the webpage. So if it is higher that a certain pixels, it should show a different view, but if its lower, then it should show a different view. To achieve this I have tried using useState and useEffect to get the window.innerWidth and then placing conditions on my return statement but this brings up a Cannot read property ‘style’ of undefined.

Code:

export default function App() {
  const [screen, setScreen] = useState(false);
  const [width, setWidth] = useState(0);
  useEffect(() => {
    setWidth(window.innerWidth);
  });

  const ref = useRef(null);

  // Reduce value if want the image to be closer to the edges
  // otherwise to the center
  const setImageLimitMovement = 1;

  const setTextLimitMovement = 4;
  const opacityRange = 400;
  // Speed text movement
  const speed = 1; // .5

  useEffect(() => {
    window.addEventListener("resize", () => {
      if (window.innerWidth !== 0) {
        setScreen(window.innerWidth);
      }
    });
  }, []);

  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 array
    const 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;

    const changeBackground = () => {
      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;
      }

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

  return (
    <>
      {/* <div style={{height:"100vh"}}></div> */}
      {width > 650 && (
        <div id="section2">
          <main ref={ref}>
            <h1 id="title" className="titles">
              {posts.Title}
            </h1>
            <section id="block1" className="blocks"></section>
            <figure id="passport">
              <img
                alt="passport"
                src="https://cdn.britannica.com/87/122087-050-1C269E8D/Cover-passport.jpg"
              />
            </figure>
            <h2 id="text1" className="titles text1">
              Random Text 1
            </h2>
          </main>
        </div>
      )}
      {width < 649 && (
        <>
          <div style={{ height: "100vh", backgroundColor: "black" }}></div>
        </>
      )}
      {/* Stop Scrolling Animation */}
      {/* <div>Content</div> */}
    </>
  );
}

Answer

The problem as identified by @lawrence-witt is because the ref object is not yet set when the useEffect runs the first time.

Here is the codesandbox link https://codesandbox.io/s/infallible-lamarr-usim6

I added some comments as I did a bit of refactor, but please feel free to pick what solves your problem.