ifit/ hooks

2020 - typescript, react

A private React hooks library created to make custom hooks to be shared with multiple webview applications at iFit. I created the "useMedia" hook which provides a JavaScript level media query for styles and rendering.

useMedia:

import { ReactNode, useState, useEffect, useCallback, useMemo } from "react"

export const media = {
  phoneMax: "(max-width: 767px)",
  tablet7Min: "(min-width: 768px)",
  tablet7Max: "(max-width: 1024px)",
  tablet10Min: "(min-width: 1025px)",
  tablet10Max: "(max-width: 1919px)",
  tablet22Min: "(min-width: 1920px)",
  landscape: "(orientation: landscape)",
  portrait: "(orientation: portrait)",
}

function useMedia(
  queries: string[],
  values: ReactNode[],
  defaultValue: ReactNode
): ReactNode {
  const mediaQueryLists = useMemo(
    () => queries.map(q => window.matchMedia(q)),
    [queries.join(",")]
  )

  const memoValues = useMemo(() => values, [values.join(",")])

  const getValue = useCallback(() => {
    const index = mediaQueryLists.findIndex(m => m.matches)
    return typeof memoValues[index] !== "undefined"
      ? memoValues[index]
      : defaultValue
  }, [defaultValue, mediaQueryLists, memoValues])

  const [value, setValue] = useState(getValue)

  useEffect(() => {
    function handler(): void {
      setValue(getValue)
    }
    mediaQueryLists.forEach(m => m.addListener(handler))
    return () => mediaQueryLists.forEach(m => m.removeListener(handler))
  }, [getValue, mediaQueryLists])

  return value
}

export default useMedia

Example usage:

import React from "react"
import useMedia, { media } from "@ifit/hooks/useMedia"

const FontSizer = () => {
  const size = useMedia(
    [media.phoneMax, media.tablet10Min],
    ["10px", "20px"],
    "14px"
  )

  return <span style={{ fontSize: size }}>Some Text</span>
}