From 05f670bb90a14cd679c1edc770e6038fcce1ef4d Mon Sep 17 00:00:00 2001 From: EnixCoda Date: Sun, 8 Mar 2020 14:27:08 +0800 Subject: [PATCH] chore: reorganize utility files --- src/components/FileExplorer.tsx | 3 +- src/components/Resizable.tsx | 3 +- src/components/SettingsBar.tsx | 2 +- src/components/SideBar.tsx | 2 +- .../settings/AccessTokenSettings.tsx | 2 +- src/components/settings/ShortcutSettings.tsx | 2 +- ...sGenerator.ts => VisibleNodesGenerator.ts} | 0 src/utils/hooks.ts | 90 ------------------- src/utils/hooks/useAsyncMemo.ts | 16 ++++ src/utils/hooks/useDidUpdate.ts | 12 +++ src/utils/hooks/useMediaStyleSheet.ts | 27 ++++++ src/utils/hooks/useOnLocationChange.ts | 10 +++ src/utils/hooks/usePrevious.ts | 9 ++ src/utils/hooks/useStates.ts | 11 +++ src/utils/hooks/useWindowSize.ts | 12 +++ ...parseIconMapCSV.tsx => parseIconMapCSV.ts} | 0 16 files changed, 105 insertions(+), 96 deletions(-) rename src/utils/{visibleNodesGenerator.ts => VisibleNodesGenerator.ts} (100%) delete mode 100644 src/utils/hooks.ts create mode 100644 src/utils/hooks/useAsyncMemo.ts create mode 100644 src/utils/hooks/useDidUpdate.ts create mode 100644 src/utils/hooks/useMediaStyleSheet.ts create mode 100644 src/utils/hooks/useOnLocationChange.ts create mode 100644 src/utils/hooks/usePrevious.ts create mode 100644 src/utils/hooks/useStates.ts create mode 100644 src/utils/hooks/useWindowSize.ts rename src/utils/{parseIconMapCSV.tsx => parseIconMapCSV.ts} (100%) diff --git a/src/components/FileExplorer.tsx b/src/components/FileExplorer.tsx index 369460c..ff544c0 100644 --- a/src/components/FileExplorer.tsx +++ b/src/components/FileExplorer.tsx @@ -9,7 +9,8 @@ import * as React from 'react' import useEvent from 'react-use/esm/useEvent' import { FixedSizeList as List, ListChildComponentProps, ListProps } from 'react-window' import { cx } from 'utils/cx' -import { useOnLocationChange, usePrevious } from 'utils/hooks' +import { useOnLocationChange } from 'utils/hooks/useOnLocationChange' +import { usePrevious } from 'utils/hooks/usePrevious' import { getCurrentPath } from 'utils/URLHelper' import { TreeNode, VisibleNodes } from 'utils/VisibleNodesGenerator' import { Icon } from './Icon' diff --git a/src/components/Resizable.tsx b/src/components/Resizable.tsx index 8a8fc0d..3be0296 100644 --- a/src/components/Resizable.tsx +++ b/src/components/Resizable.tsx @@ -4,7 +4,8 @@ import * as React from 'react' import { cx } from 'utils/cx' import { bodySpacingClassName } from 'utils/DOMHelper' import * as features from 'utils/features' -import { useMediaStyleSheet, useWindowSize } from 'utils/hooks' +import { useMediaStyleSheet } from 'utils/hooks/useMediaStyleSheet' +import { useWindowSize } from 'utils/hooks/useWindowSize' export type Size = number type Props = { diff --git a/src/components/SettingsBar.tsx b/src/components/SettingsBar.tsx index a8da63a..90e3420 100644 --- a/src/components/SettingsBar.tsx +++ b/src/components/SettingsBar.tsx @@ -2,7 +2,7 @@ import { Icon } from 'components/Icon' import { VERSION } from 'env' import * as React from 'react' import { Config } from 'utils/configHelper' -import { useStates } from 'utils/hooks' +import { useStates } from 'utils/hooks/useStates' import { AccessTokenSettings } from './settings/AccessTokenSettings' import { FileTreeIconSettings } from './settings/FileTreeIconSettings' import { ShortcutSettings } from './settings/ShortcutSettings' diff --git a/src/components/SideBar.tsx b/src/components/SideBar.tsx index 68347b4..9b6454a 100644 --- a/src/components/SideBar.tsx +++ b/src/components/SideBar.tsx @@ -15,7 +15,7 @@ import useEvent from 'react-use/esm/useEvent' import { cx } from 'utils/cx' import * as DOMHelper from 'utils/DOMHelper' import { JSONRequest, parseURLSearch } from 'utils/general' -import { useDidUpdate } from 'utils/hooks' +import { useDidUpdate } from 'utils/hooks/useDidUpdate' import * as keyHelper from 'utils/keyHelper' import * as URLHelper from 'utils/URLHelper' diff --git a/src/components/settings/AccessTokenSettings.tsx b/src/components/settings/AccessTokenSettings.tsx index 8aa9c2b..afaa1c6 100644 --- a/src/components/settings/AccessTokenSettings.tsx +++ b/src/components/settings/AccessTokenSettings.tsx @@ -2,7 +2,7 @@ import { wikiLinks } from 'components/SettingsBar' import { useConfigs } from 'containers/ConfigsContext' import { oauth } from 'env' import * as React from 'react' -import { useStates } from 'utils/hooks' +import { useStates } from 'utils/hooks/useStates' const ACCESS_TOKEN_REGEXP = /^[0-9a-f]{40}$/ diff --git a/src/components/settings/ShortcutSettings.tsx b/src/components/settings/ShortcutSettings.tsx index f7454b0..05a5b7c 100644 --- a/src/components/settings/ShortcutSettings.tsx +++ b/src/components/settings/ShortcutSettings.tsx @@ -1,7 +1,7 @@ import { useConfigs } from 'containers/ConfigsContext' import * as React from 'react' import { friendlyFormatShortcut } from 'utils/general' -import { useStates } from 'utils/hooks' +import { useStates } from 'utils/hooks/useStates' import * as keyHelper from 'utils/keyHelper' type Props = {} diff --git a/src/utils/visibleNodesGenerator.ts b/src/utils/VisibleNodesGenerator.ts similarity index 100% rename from src/utils/visibleNodesGenerator.ts rename to src/utils/VisibleNodesGenerator.ts diff --git a/src/utils/hooks.ts b/src/utils/hooks.ts deleted file mode 100644 index 75aa7d5..0000000 --- a/src/utils/hooks.ts +++ /dev/null @@ -1,90 +0,0 @@ -import * as React from 'react' -import useLocation from 'react-use/esm/useLocation' -import { createStyleSheet, setStyleSheetMedia } from './general' - -export function useWindowSize( - callback: (width: number) => void, - deps?: ReadonlyArray | undefined, -) { - React.useEffect(() => { - const resizeListener: (this: Window, ev: UIEvent) => void = () => callback(window.innerWidth) - - window.addEventListener('resize', resizeListener) - return () => window.removeEventListener('resize', resizeListener) - }, deps) -} - -export function useMediaStyleSheet( - content: string, - getMediaQuery: (width: number) => string[], - size: number, -) { - const style = React.useRef() - - // this order may prevent first effect actually occur at first time - React.useEffect(() => { - setSheetMedia() - }, [size]) - React.useEffect(() => { - style.current = createStyleSheet(content) - setSheetMedia() - }, []) - - function setSheetMedia() { - if (style.current) - setStyleSheetMedia( - style.current, - getMediaQuery(size) - .map(query => `(${query})`) - .join(' and '), - ) - } -} - -export function usePrevious(newValue: T) { - const previousRef = React.useRef(newValue) - React.useEffect(() => { - previousRef.current = newValue - }) - return previousRef.current -} - -export function useStates( - initialState: S | (() => S), -): { val: S; set: React.Dispatch> } { - const [val, set] = React.useState(initialState) - return { val, set } -} - -export function useAsyncMemo( - factory: (dependencies: D) => T | Promise, - deps: D, - initialValue: T, -): T { - const firstTime = React.useRef(true) - const state = useStates(() => initialValue) - React.useEffect(() => { - if (firstTime.current) firstTime.current = false - Promise.resolve(factory(deps)).then(consumed => state.set(() => consumed)) - }, deps) - return state.val -} - -export function useDidUpdate(effect: React.EffectCallback, deps?: React.DependencyList) { - const firstTime = React.useRef(true) - React.useEffect(() => { - if (firstTime.current) { - firstTime.current = false - return - } - return effect() - }, deps) -} - -export function useOnLocationChange( - callback: React.EffectCallback, - extraDeps: React.DependencyList = [], -) { - const { href, pathname, search } = useLocation() - React.useEffect(callback, [href, pathname, search, ...extraDeps]) -} diff --git a/src/utils/hooks/useAsyncMemo.ts b/src/utils/hooks/useAsyncMemo.ts new file mode 100644 index 0000000..e6e0234 --- /dev/null +++ b/src/utils/hooks/useAsyncMemo.ts @@ -0,0 +1,16 @@ +import * as React from 'react' +import { useStates } from './useStates' + +export function useAsyncMemo( + factory: (dependencies: D) => T | Promise, + deps: D, + initialValue: T, +): T { + const firstTime = React.useRef(true) + const state = useStates(() => initialValue) + React.useEffect(() => { + if (firstTime.current) firstTime.current = false + Promise.resolve(factory(deps)).then(consumed => state.set(() => consumed)) + }, deps) + return state.val +} diff --git a/src/utils/hooks/useDidUpdate.ts b/src/utils/hooks/useDidUpdate.ts new file mode 100644 index 0000000..477199f --- /dev/null +++ b/src/utils/hooks/useDidUpdate.ts @@ -0,0 +1,12 @@ +import * as React from 'react' + +export function useDidUpdate(effect: React.EffectCallback, deps?: React.DependencyList) { + const firstTime = React.useRef(true) + React.useEffect(() => { + if (firstTime.current) { + firstTime.current = false + return + } + return effect() + }, deps) +} diff --git a/src/utils/hooks/useMediaStyleSheet.ts b/src/utils/hooks/useMediaStyleSheet.ts new file mode 100644 index 0000000..40d3c76 --- /dev/null +++ b/src/utils/hooks/useMediaStyleSheet.ts @@ -0,0 +1,27 @@ +import * as React from 'react' +import { createStyleSheet, setStyleSheetMedia } from '../general' + +export function useMediaStyleSheet( + content: string, + getMediaQuery: (width: number) => string[], + size: number, +) { + const style = React.useRef() + // this order may prevent first effect actually occur at first time + React.useEffect(() => { + setSheetMedia() + }, [size]) + React.useEffect(() => { + style.current = createStyleSheet(content) + setSheetMedia() + }, []) + function setSheetMedia() { + if (style.current) + setStyleSheetMedia( + style.current, + getMediaQuery(size) + .map(query => `(${query})`) + .join(' and '), + ) + } +} diff --git a/src/utils/hooks/useOnLocationChange.ts b/src/utils/hooks/useOnLocationChange.ts new file mode 100644 index 0000000..685aa47 --- /dev/null +++ b/src/utils/hooks/useOnLocationChange.ts @@ -0,0 +1,10 @@ +import * as React from 'react' +import useLocation from 'react-use/esm/useLocation' + +export function useOnLocationChange( + callback: React.EffectCallback, + extraDeps: React.DependencyList = [], +) { + const { href, pathname, search } = useLocation() + React.useEffect(callback, [href, pathname, search, ...extraDeps]) +} diff --git a/src/utils/hooks/usePrevious.ts b/src/utils/hooks/usePrevious.ts new file mode 100644 index 0000000..1d4dd4b --- /dev/null +++ b/src/utils/hooks/usePrevious.ts @@ -0,0 +1,9 @@ +import * as React from 'react' + +export function usePrevious(newValue: T) { + const previousRef = React.useRef(newValue) + React.useEffect(() => { + previousRef.current = newValue + }) + return previousRef.current +} diff --git a/src/utils/hooks/useStates.ts b/src/utils/hooks/useStates.ts new file mode 100644 index 0000000..0e2eb41 --- /dev/null +++ b/src/utils/hooks/useStates.ts @@ -0,0 +1,11 @@ +import * as React from 'react' + +export function useStates( + initialState: S | (() => S), +): { + val: S + set: React.Dispatch> +} { + const [val, set] = React.useState(initialState) + return { val, set } +} diff --git a/src/utils/hooks/useWindowSize.ts b/src/utils/hooks/useWindowSize.ts new file mode 100644 index 0000000..477f008 --- /dev/null +++ b/src/utils/hooks/useWindowSize.ts @@ -0,0 +1,12 @@ +import * as React from 'react' + +export function useWindowSize( + callback: (width: number) => void, + deps?: ReadonlyArray | undefined, +) { + React.useEffect(() => { + const resizeListener: (this: Window, ev: UIEvent) => void = () => callback(window.innerWidth) + window.addEventListener('resize', resizeListener) + return () => window.removeEventListener('resize', resizeListener) + }, deps) +} diff --git a/src/utils/parseIconMapCSV.tsx b/src/utils/parseIconMapCSV.ts similarity index 100% rename from src/utils/parseIconMapCSV.tsx rename to src/utils/parseIconMapCSV.ts