Make Your React Apps Responsive with a Custom Hook

? This post originally appeared on ReedBarger.com.

How do you make your React applications responsive for any sized device? Let’s see how to do so by making our own custom React hook.

At the top of my React site is a Header component. As I decrease t…


This content originally appeared on DEV Community and was authored by Reed Barger

? This post originally appeared on ReedBarger.com.

How do you make your React applications responsive for any sized device? Let's see how to do so by making our own custom React hook.

At the top of my React site is a Header component. As I decrease the size of the page, I want to show less links:

resizing window to show header

To do this we could use a media query with CSS, or we could use a custom React hook to give us the current size of the page and hide or show the links in our JSX.

Previously, I was using a hook from the a library called react-use to add this functionality.

Instead of bringing an entire third-party library, however, I decided to create my own hook that would that provide the dimensions of the window, both the width and height. I called this hook useWindowSize.

Interested in creating impressive React apps that use custom React hooks like this one? Check out The React Bootcamp

Creating the hook

First, we’ll create a new file .js in our utilities (utils) folder, the same name as the hook useWindowSize and I’ll import React (to use hooks) while exporting the custom hook.

// utils/useWindowSize.js

import React from "react";

export default function useWindowSize() {}

Now since I’m using this within a Gatsby site, which is server rendered, I need to get the size of the window, but we may not have access to it because we’re on the server. To check and make sure we’re not on the server, we can see if type of window is not equal to the string undefined.

In which case we can return to a default width and height for a browser, say, 1200 and 800 within an object:

// utils/useWindowSize.js

import React from "react";

export default function useWindowSize() {
  if (typeof window !== "undefined") {
    return { width: 1200, height: 800 };
  }
}

Getting the width and height from window

And assuming we are on the client and can get the window, we can take the useEffect hook to perform a side effect by interacting with window. We’ll include an empty dependencies array to make sure the effect function is called only once the component (that this hook is called in) is mounted.

To find out the window width and height, we can add an event listener and listen for the resize event. And whenever the browser sizes change, we can update a piece of state (created with useState), which we’ll call windowSize and the setter to update it will be setWindowSize.

// utils/useWindowSize.js

import React from "react";

export default function useWindowSize() {
  if (typeof window !== "undefined") {
    return { width: 1200, height: 800 };
  }

  const [windowSize, setWindowSize] = React.useState();

  React.useEffect(() => {
    window.addEventListener("resize", () => {
      setWindowSize({ width: window.innerWidth, height: window.innerHeight });
    });
  }, []);
}

When the window is resized, the callback will be called and the windowSize state will be updated with the current window dimensions. To get that, we set the width to window.innerWidth, and height, window.innerHeight.

Adding SSR support

However, the code as we have it here will not work. And the reason is because a key rule of hooks is that they cannot be called conditionally. As a result, we cannot have a conditional above our useState or useEffect hook, before they are called.

So to fix this, we’ll set the initial value of useState conditionally. We’ll create a variable called isSSR, which will perform the same check to see if the window is not equal to the string undefined.

And we’ll use a ternary to set the width and height by first checking to see if we’re on the server. If we are we’ll use the default value and if not, we’ll use window.innerWidth and window.innerHeight.

// utils/useWindowSize.js

import React from "react";

export default function useWindowSize() {
  // if (typeof window !== "undefined") {
  // return { width: 1200, height: 800 };
  // }
  const isSSR = typeof window !== "undefined";
  const [windowSize, setWindowSize] = React.useState({
    width: isSSR ? 1200 : window.innerWidth,
    height: isSSR ? 800 : window.innerHeight,
  });

  React.useEffect(() => {
    window.addEventListener("resize", () => {
      setWindowSize({ width: window.innerWidth, height: window.innerHeight });
    });
  }, []);
}

Then finally, we need to think about when our components unmount. What do we need to do? We need to remove our resize listener.

Removing resize event listener

You can do that by returning a function from useEffectand we will remove the listener with window.removeEventListener.

// utils/useWindowSize.js

import React from "react";

export default function useWindowSize() {
  // if (typeof window !== "undefined") {
  // return { width: 1200, height: 800 };
  // }
  const isSSR = typeof window !== "undefined";
  const [windowSize, setWindowSize] = React.useState({
    width: isSSR ? 1200 : window.innerWidth,
    height: isSSR ? 800 : window.innerHeight,
  });

  React.useEffect(() => {
    window.addEventListener("resize", () => {
      setWindowSize({ width: window.innerWidth, height: window.innerHeight });
    });

    return () => {
      window.removeEventListener("resize", () => {
        setWindowSize({ width: window.innerWidth, height: window.innerHeight });
      });
    };
  }, []);
}

But since we need a reference to the same function, not two different ones as we have here. To do that, we’ll create a shared callback function to both of the listeners called changeWindowSize.

And finally, at the end of the hook, we will return our windowSize state. And that’s it.

// utils/useWindowSize.js

import React from "react";

export default function useWindowSize() {
  const isSSR = typeof window !== "undefined";
  const [windowSize, setWindowSize] = React.useState({
    width: isSSR ? 1200 : window.innerWidth,
    height: isSSR ? 800 : window.innerHeight,
  });

  function changeWindowSize() {
    setWindowSize({ width: window.innerWidth, height: window.innerHeight });
  }

  React.useEffect(() => {
    window.addEventListener("resize", changeWindowSize);

    return () => {
      window.removeEventListener("resize", changeWindowSize);
    };
  }, []);

  return windowSize;
}

Usage

To use the hook, we just need to import it where we need, call it, and use the width wherever we want to hide or show certain elements.

In my case, this is at the 500px mark. There, I want to hide all of the other links and only show the Join Now button, like you see in the example above:

// components/StickyHeader.js

import React from "react";
import useWindowSize from "../utils/useWindowSize";

function StickyHeader() {
  const { width } = useWindowSize();

  return (
    <div>
      {/* visible only when window greater than 500px */}
      {width > 500 && (
        <>
          <div onClick={onTestimonialsClick} role="button">
            <span>Testimonials</span>
          </div>
          <div onClick={onPriceClick} role="button">
            <span>Price</span>
          </div>
          <div>
            <span onClick={onQuestionClick} role="button">
              Question?
            </span>
          </div>
        </>
      )}
      {/* visible at any window size */}
      <div>
        <span className="primary-button" onClick={onPriceClick} role="button">
          Join Now
        </span>
      </div>
    </div>
  );
}

This hook will work on any server rendered React app, such as Gatsby and Next.js.

Enjoy this post? Join The React Bootcamp

The React Bootcamp takes everything you should know about learning React and bundles it into one comprehensive package, including videos, cheatsheets, plus special bonuses.

Gain the insider information hundreds of developers have already used to master React, find their dream jobs, and take control of their future:

The React Bootcamp

Click here to be notified when it opens


This content originally appeared on DEV Community and was authored by Reed Barger


Print Share Comment Cite Upload Translate Updates
APA

Reed Barger | Sciencx (2021-04-12T14:19:30+00:00) Make Your React Apps Responsive with a Custom Hook. Retrieved from https://www.scien.cx/2021/04/12/make-your-react-apps-responsive-with-a-custom-hook/

MLA
" » Make Your React Apps Responsive with a Custom Hook." Reed Barger | Sciencx - Monday April 12, 2021, https://www.scien.cx/2021/04/12/make-your-react-apps-responsive-with-a-custom-hook/
HARVARD
Reed Barger | Sciencx Monday April 12, 2021 » Make Your React Apps Responsive with a Custom Hook., viewed ,<https://www.scien.cx/2021/04/12/make-your-react-apps-responsive-with-a-custom-hook/>
VANCOUVER
Reed Barger | Sciencx - » Make Your React Apps Responsive with a Custom Hook. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2021/04/12/make-your-react-apps-responsive-with-a-custom-hook/
CHICAGO
" » Make Your React Apps Responsive with a Custom Hook." Reed Barger | Sciencx - Accessed . https://www.scien.cx/2021/04/12/make-your-react-apps-responsive-with-a-custom-hook/
IEEE
" » Make Your React Apps Responsive with a Custom Hook." Reed Barger | Sciencx [Online]. Available: https://www.scien.cx/2021/04/12/make-your-react-apps-responsive-with-a-custom-hook/. [Accessed: ]
rf:citation
» Make Your React Apps Responsive with a Custom Hook | Reed Barger | Sciencx | https://www.scien.cx/2021/04/12/make-your-react-apps-responsive-with-a-custom-hook/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.