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 (кидать промисы в исключения).
Заметка о хуке useSyncExternalStore