Open1

宣言的にブレイクポイント検出を行いたい

cyamycyamy

型情報はもっと上手に扱えるはず。

type UseEffectTarget = {
  [key: string]: string | number | boolean;
};

type Queries = {
  [key: string]: MediaQueryList;
};

const effectWatcher = (
  target: UseEffectTarget,
  props: string,
  callback: () => void,
) => {
  let value = target[props];

  Object.defineProperty(target, props, {
    get: () => value,
    set: (newValue) => {
      value = newValue;
      callback();
    },
    configurable: true,
  });
};

const useEffect = (callback: () => void, target: UseEffectTarget) => {
  Object.entries(target).forEach((current) => {
    const [prop] = [...current];
    effectWatcher(target, prop, callback);
  });
};

const createQueryStats = (queries: Queries): UseEffectTarget => {
  return Object.entries(queries).reduce((prev, current) => {
    const [size, query] = [...current];
    return {
      ...prev,
      [size]: query.matches,
    };
  }, {});
};

const setMediaOnchangeEvents = (
  queries: Queries,
  queryStats: UseEffectTarget,
) => {
  Object.entries(queries).forEach((current) => {
    const [size, query] = [...current];
    query.onchange = (event) => {
      queryStats[size] = event.matches;
    };
  });
};

const showCurrentBreakpoint = (queries: UseEffectTarget) => {
  queries.lg
    ? console.log('lg layout')
    : queries.md
      ? console.log('md layout')
      : console.log('sm layout');
};

const main = () => {
  const queries: Queries = {
    lg: window.matchMedia('(min-width: 1024px)'),
    md: window.matchMedia('(min-width: 768px)'),
    sm: window.matchMedia('(min-width: 0px)'),
  };
  const queryStats: UseEffectTarget = createQueryStats(queries);

  // 初回実行時
  setMediaOnchangeEvents(queries, queryStats);
  showCurrentBreakpoint(queryStats);

  // Breakpoint が変更された場合に実行
  useEffect(() => {
    showCurrentBreakpoint(queryStats);
  }, queryStats);
};

main();

参考: https://qiita.com/ymgd-a/items/5a6bb79e90aa5633d026