Pull to refresh

Comments 4

В subscribeMediaQuery ошибка. Нужно дописать return

Еще один вариант хука useMediaQuery:

import { useCallback, useSyncExternalStore } from "react";

function useMediaQuery(query) {
  const subscribe = useCallback(
    (callback) => {
      const matchMedia = window.matchMedia(query);

      matchMedia.addEventListener("change", callback);
      return () => {
        matchMedia.removeEventListener("change", callback);
      };
    },
    [query]
  );

  const getSnapshot = () => {
    return window.matchMedia(query).matches;
  };

  const getServerSnapshot = () => {
    throw Error("useMediaQuery is a client-only hook");
  };

  return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
}

export default useMediaQuery;

Примеры использования:

const isSm = useMediaQuery("(max-width : 768px)");
const isMd = useMediaQuery(
  "(min-width : 769px) and (max-width : 992px)"
);
const isLg = useMediaQuery(
  "(min-width : 993px) and (max-width : 1200px)"
);
const isXl = useMediaQuery(
  "(min-width : 1201px)"
);

Столкнулся с особенностью применения useSyncExternalStore. Берем данные с помощью этого хука, а после вызываем действие внешнего хранилища, которое приводит к синхронному изменению состояния и тем самым сразу оповещает useSyncExternalStore. Будет ошибка рендера, типа нам нельзя менять внешнее состояние пока рендерится компонент. Как минимум нужно установку состояния вызывать в микротакске, например в Promise.resolve().then(...).
А хук useSelector использует useState, чтобы заставить компонент рендериться после уведомления об изменении внешнего состояния. И это позволяет синхронно менять внешнее состояние. С другой стороны useSelector создаёт ошибки, если асинхронные действия внешнего хранилища интегрировать со Suspense (кидать промисы в исключения).

Sign up to leave a comment.