React Hooks for Managing Media Queries

Hooks provide a way to use state and other React features without using class components.

useMediaQuery() Hook

This simple hook facilitates the sharing and rendering of components, logic, and styling based on media queries directly from your JSX code.

Creating the Hook

hooks/useMediaQuery.jsx

import { useState, useEffect } from "react";

const useMediaQuery = (query) => {
  const [matches, setMatches] = useState(false);

  useEffect(() => {
    const media = window.matchMedia(query);
    if (media.matches !== matches) {
      setMatches(media.matches);
    }
    const listener = () => setMatches(media.matches);
    window.addEventListener("resize", listener);
    return () => window.removeEventListener("resize", listener);
  }, [matches, query]);

  return matches;
}

export default useMediaQuery;

Using the Hook

App.js

import React from "react";
import "./index.css";
import useMediaQuery from "./hooks/useMediaQuery";

function App() {
  // Define the media query
  const isDesktop = useMediaQuery('(min-width: 960px)');

  return (
    <div className="App">
      {/* Conditional rendering based on the media query */}
      {isDesktop ? <h1>Desktop</h1> : <h1>Mobile</h1>}
      <Navbar isDesktop={isDesktop}/>
    </div>
  );
}

// Navbar component with conditional styling
const Navbar = ({isDesktop}) => (
  <nav className={`base ${isDesktop ? "desktop" : "mobile"}`}>
    {/* SVG icon repeated multiple times */}
    <Icon />
    <Icon />
    <Icon />
    <Icon />
  </nav>
);


// SVG icon component
const Icon = () => (
  <svg viewBox="0 0 512 512">
    {/* SVG path */}
    <path
      fill="currentColor"
      d="M448 96h-64l-64-64v134.4a96 96 0 0 0 192 0V32zm-72 80a16 16 0 1 1 16-16 16 16 0 0 1-16 16zm80 0a16 16 0 1 1 16-16 16 16 0 0 1-16 16zm-165.41 16a204.07 204.07 0 0 0-34.59 2.89V272l-43.15-64.73a183.93 183.93 0 0 0-44.37 26.17L192 304l-60.94-30.47L128 272v-80a96.1 96.1 0 0 0-96-96 32 32 0 0 0 0 64 32 32 0 0 1 32 32v256a64.06 64.06 0 0 0 64 64h176a16 16 0 0 0 16-16v-16a32 32 0 0 0-32-32h-32l128-96v144a16 16 0 0 0 16 16h32a16 16 0 0 0 16-16V289.86a126.78 126.78 0 0 1-32 4.54c-61.81 0-113.52-44.05-125.41-102.4z"
    />
    {/* Additional SVG path */}
    <path
      fill="currentColor"
      d="M376 144a16 16 0 1 0 16 16 16 16 0 0 0-16-16zm80 0a16 16 0 1 0 16 16 16 16 0 0 0-16-16zM131.06 273.53L192 304l-23.52-70.56a192.06 192.06 0 0 0-37.42 40.09zM256 272v-77.11a198.62 198.62 0 0 0-43.15 12.38z"
    />
  </svg>
);

export default App;

Optional CSS Styling

file_type_css index.css

:root {
  --dark: #151718;
  --text: #00c3ff;
  --svg: #ea60ff;
  --nav: #212223;
  font-size: 1rem;
}

body {
  margin: 0;
  font-family: sans-serif;
  background-color: var(--dark);
}

.app {
  position: absolute;
  margin: auto;
  top: 25%;
  width: 100%;
  display: flex;
  align-items: center;
  flex-direction: column;
  justify-content: center;
}

.app h1 {
  color: var(--text);
  font-size: 4rem;
  font-weight: 400;
}

.app svg {
  color: #ea60ff;
  margin: auto;
  height: auto;
  transition: all 250ms ease;
}

.base {
  position: fixed;
  display: flex;
  align-items: center;
  justify-content: space-evenly;
  background-color: var(--nav);
  transition: all 250ms ease;
}

.desktop {
  top: 0;
  left: 0;
  width: 5rem;
  height: 100vh;
  flex-direction: column;
}

.mobile {
  bottom: 0;
  height: 5rem;
  width: 100vw;
}

Comments

Load Comments