Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
208 changes: 104 additions & 104 deletions src/hooks/useMediaQuery/index.ts
Original file line number Diff line number Diff line change
@@ -1,122 +1,122 @@
import React, { useEffect, useMemo, useState, useCallback, useRef } from "react";
import React, { useEffect, useMemo, useState, useCallback, useRef } from 'react';

interface IResponsibleHookConfig {
[type: string]: string;
[type: string]: string;
}

type Order = 'ASC' | 'DESC';

function checkBrowser() {
if (typeof window !== undefined) {
return true;
}
return false;
return typeof window !== undefined;
}

function checkPC() {
const PC_OS = "win16|win32|win64|mac|macintel";
if (navigator.platform && PC_OS.indexOf(navigator.platform.toLowerCase()) >= 0) {
return true;
} else {
return false;
}
const PC_OS = 'win16|win32|win64|mac|macintel';
return !!(navigator.platform && PC_OS.indexOf(navigator.platform.toLowerCase()) >= 0);
}

function checkConfig(config: any) {
if (!config) {
throw new Error("Need to config");
function checkConfig(config: IResponsibleHookConfig) {
if (!config) {
throw new Error('Need to config');
}
}

function sortConfigWithSize(config: IResponsibleHookConfig, order: Order = 'ASC') {
const configEntries = Object.entries(config);
configEntries.sort((before, after) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🏷Tip
array.sort()를 실행하면 내부적으로 정렬된 값이 array에 반영되어 따로 할당할 필요가 없다.
이 부분 새롭게 알아갑니다. 감사합니다.

const beforeSize = Number(before[1].replace('px', ''));
const afterSize = Number(after[1].replace('px', ''));
if (!beforeSize || !afterSize || Number.isNaN(beforeSize) || Number.isNaN(afterSize)) {
throw new Error('You need to use px in size');
}
if (order === 'ASC') return beforeSize - afterSize;
return afterSize - beforeSize;
});

return Object.fromEntries(configEntries);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🏷 Object.fromEntries()
translate key-value to object like ["key","value"] => { key : value }

}

function sortConfigWithSize(config: IResponsibleHookConfig, order: "ASC" | "DESC" = "ASC") {
const sortedConfig = {};
const configEntries = Object.entries(config);
const sortedConfigEntries = configEntries.sort((before, after) => {
const beforeSize = Number(before[1].replace("px", ""));
const afterSize = Number(after[1].replace("px", ""));
if (!before || !afterSize) {
throw new Error("You need to use px in size");
export const useMediaQuery = (
config: IResponsibleHookConfig = {},
initial: string
): [string, any?] => {
try {
if (!checkBrowser()) {
throw new Error('It is not broswer environment, you need to use this in browser environment');
}
const [mediaType, setMediaType] = useState<string>('');
const latestType = useRef<string>('');

const sortedConfig = useMemo(() => sortConfigWithSize(config, 'DESC'), [config]);
const configKeys = useMemo(() => Object.keys(sortedConfig), [sortedConfig]);

const eventHandlerGenerator = useCallback(
(type: string) => (event: MediaQueryListEvent) => {
if (event.matches) {
setMediaType(prev => {
latestType.current = prev;
return type;
});
} else {
const index = configKeys.findIndex(value => value === type);
if (index - 1 >= 0) {
setMediaType(configKeys[index - 1]);
} else {
setMediaType(initial);
}
}
return order === "ASC" ? beforeSize - afterSize : afterSize - beforeSize;
});
sortedConfigEntries.forEach(item => {
Object.assign(sortedConfig, { [item[0]]: item[1] });
});
return sortedConfig;
}
},
[initial, configKeys]
);

const mediaQuerys = useMemo(
() =>
configKeys.map(key => {
const mediaQuery = window.matchMedia(`screen and (max-width: ${config[key]})`);
return { mediaQuery, eventHandler: eventHandlerGenerator(key), type: key };
}),
[configKeys]
);

export const useMediaQuery = (config: IResponsibleHookConfig, initial: string): [string, any?] => {
try {
if (!checkBrowser()) {
throw new Error("It is not broswer environment, you need to use this in browser environment");
useEffect(() => {
const shouldInitial = !mediaQuerys.reverse().some(item => {
const { mediaQuery, type } = item;
if (mediaQuery.matches) {
setMediaType(type);
latestType.current = type;
return true;
}
const [mediaType, setMediaType] = useState<string>("");
const latestType = useRef<string>("");

checkConfig(config);

const sortedConfig = useMemo(() => sortConfigWithSize(config, "DESC"), [config]);
const configKeys = useMemo(() => Object.keys(sortedConfig), [sortedConfig]);

const eventHandlerGenerator = useCallback(
(type: string) => (event: MediaQueryListEvent) => {
if (event.matches) {
setMediaType(prev => {
latestType.current = prev;
return type;
});
} else {
const index = configKeys.findIndex(value => value === type);
if (index && index - 1 >= 0) {
setMediaType(configKeys[index - 1]);
} else {
setMediaType(initial);
}
}
},
[initial, configKeys]
);

const mediaQuerys = useMemo(
() =>
configKeys.map(key => {
const mediaQuery = window.matchMedia(`screen and (max-width: ${config[key]})`);
return { mediaQuery, eventHandler: eventHandlerGenerator(key), type: key };
}),
[configKeys]
);

useEffect(() => {
const shouldInitial = !mediaQuerys.reverse().some(item => {
const { mediaQuery, type } = item;
if (mediaQuery.matches) {
setMediaType(type);
latestType.current = type;
return true;
}
return false;
});
if (shouldInitial) {
setMediaType(initial);
}
}, [mediaQuerys, initial]);

useEffect(() => {
if (checkPC()) {
mediaQuerys.forEach(item => {
const { mediaQuery, eventHandler } = item;
mediaQuery.addEventListener("change", eventHandler);
});

return () => {
mediaQuerys.forEach(item => {
const { mediaQuery, eventHandler } = item;
mediaQuery.removeEventListener("change", eventHandler);
});
};
}
}, [mediaQuerys]);
return [mediaType];
} catch (error) {
return ["Error", error];
}
return false;
});
if (shouldInitial) {
setMediaType(initial);
}
}, [mediaQuerys, initial]);

useEffect(() => {
if (checkPC()) {
mediaQuerys.forEach(item => {
const { mediaQuery, eventHandler } = item;
mediaQuery.addEventListener('change', eventHandler);
});

return () => {
mediaQuerys.forEach(item => {
const { mediaQuery, eventHandler } = item;
mediaQuery.removeEventListener('change', eventHandler);
});
};
}
}, [mediaQuerys]);

useEffect(() => {
checkConfig(config);
}, [config]);

return [mediaType];
} catch (error) {
return ['Error', error];
}
};

export default useMediaQuery;