Skip to content

Commit 71bc3c9

Browse files
committed
feat: added hooks useScript, useDeepCompareEffect, useEventListener, useOnScreen, useWindowSize
1 parent fa73fd2 commit 71bc3c9

File tree

9 files changed

+955
-799
lines changed

9 files changed

+955
-799
lines changed

package-lock.json

Lines changed: 815 additions & 790 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,32 @@
11
{
22
"name": "cats-react-hooks",
3-
"version": "1.0.4",
3+
"version": "1.2.0",
44
"description": "",
55
"main": "dist/index.js",
6-
"types": "./types",
6+
"types": "dist/",
77
"repository": {
88
"type": "git",
99
"url": "git+https://github.com/iojuedioe9rd/cats-react-hooks.git"
1010
},
1111
"scripts": {
1212
"test": "echo \"Error: no test specified\" && exit 1",
13-
"build": "tsc src/index.ts --declaration --declarationDir ./types --outDir ./dist --target ES6 --allowSyntheticDefaultImports",
13+
"build": "tsc src/index.ts --declaration --declarationDir dist --outDir ./dist --target ES6 --allowSyntheticDefaultImports",
1414
"commit": "git-cz"
1515
},
1616
"keywords": [],
1717
"author": "Cats Studio",
1818
"license": "MIT",
1919
"dependencies": {
20-
"react": "^18.2.0",
21-
"tsc": "^2.0.4",
22-
"typescript": "^5.2.2"
20+
"lodash": "^4.17.21",
21+
"react": "^18.2.0"
2322
},
2423
"devDependencies": {
24+
"@types/lodash": "^4.14.200",
2525
"@types/react": "^18.2.31",
2626
"cz-conventional-changelog": "^3.3.0",
27-
"semantic-release": "^22.0.5"
27+
"semantic-release": "^22.0.5",
28+
"tsc": "^2.0.4",
29+
"typescript": "^5.2.2"
2830
},
2931
"config": {
3032
"commitizen": {

src/index.ts

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,17 @@ import {useJSON as useJSONTMP} from "./useJSON"
55
import { useToggle as useToggleTMP } from "./useToggle";
66
import { useTimeout as useTimeoutTMP } from "./useTimeout";
77
import { useDebounce as useDebounceTMP } from "./useDebounce";
8-
import React, { SetStateAction } from "react";
8+
import React, { EffectCallback, SetStateAction } from "react";
99
import { useUpdateEffect as useUpdateEffectTMP } from "./useUpdateEffect";
1010
import { useArray as useArrayTMP, FilterCallback } from "./useArray";
1111
import {usePrevious as usePreviousTMP} from "./usePrevious"
1212
import {useStateWithHistory as useStateWithHistoryTMP} from "./useStateWithHistory"
1313
import useAsyncTMP from "./useAsync"
14+
import useScriptTMP from "./useScript";
15+
import useDeepCompareEffectTMP from "./useDeepCompareEffect"
16+
import useEventListenerTMP from "./useEventListener";
17+
import useOnScreenTMP from "./useOnScreen";
18+
import useWindowSizeTMP from "./useWindowSize"
1419

1520
export function useLocalStorage<T>(key: string, initialValue: T | (() => T))
1621
{
@@ -93,4 +98,32 @@ export function useAsync<T>(callback: () => Promise<SetStateAction<T | undefined
9398
export function useFetch<T>(url: string | URL, options: RequestInit = {}, dependencies: React.DependencyList = [])
9499
{
95100
return useFetchTMP<T>(url.toString(), options, dependencies)
101+
}
102+
103+
export function useScript(url: string | URL)
104+
{
105+
return useScriptTMP(url.toString())
106+
}
107+
108+
export function useDeepCompareEffect(callback: EffectCallback, dependencies?: React.DependencyList)
109+
{
110+
return useDeepCompareEffectTMP(callback, dependencies)
111+
}
112+
113+
export function useEventListener(
114+
eventType: string,
115+
callback: (e: Event) => (void | Promise<void>),
116+
element = window
117+
)
118+
{
119+
return useEventListenerTMP(eventType, callback, element)
120+
}
121+
export function useOnScreen(ref: React.MutableRefObject<HTMLElement>, rootMargin = "0px")
122+
{
123+
return useOnScreenTMP(ref, rootMargin)
124+
}
125+
126+
export function useWindowSize()
127+
{
128+
return useWindowSizeTMP()
96129
}

src/useDeepCompareEffect.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { EffectCallback, useEffect, useRef } from "react";
2+
import isEqual from "lodash/isEqual"
3+
4+
export default function useDeepCompareEffect(callback: EffectCallback, dependencies?: React.DependencyList)
5+
{
6+
const currentDependenciesRef = useRef<React.DependencyList | undefined>()
7+
8+
if(!isEqual(currentDependenciesRef.current, dependencies))
9+
{
10+
currentDependenciesRef.current = dependencies
11+
}
12+
13+
useEffect(callback, [currentDependenciesRef.current])
14+
}

src/useEventListener.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { useEffect, useRef } from "react";
2+
3+
4+
export default function useEventListener(
5+
eventType: string,
6+
callback: (e: Event) => (void | Promise<void>),
7+
element = window
8+
)
9+
{
10+
const callbackRef = useRef(callback)
11+
12+
useEffect(() => {
13+
callbackRef.current = callback
14+
}, [callback])
15+
16+
useEffect(() => {
17+
const handler = (e: Event) => callbackRef.current(e)
18+
element.addEventListener(eventType, handler)
19+
20+
return () => element.removeEventListener(eventType, handler)
21+
}, [eventType, element])
22+
}

src/useOnScreen.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import isNull from "lodash/isNull";
2+
import React, { useEffect, useState } from "react";
3+
4+
export default function useOnScreen(ref: React.MutableRefObject<HTMLElement>, rootMargin = "0px")
5+
{
6+
const [isVisible, setIsVisible] = useState(false)
7+
8+
useEffect(() => {
9+
console.log(ref.current)
10+
if(isNull( ref.current)) return
11+
const observer = new IntersectionObserver(([entry]) => setIsVisible(entry.isIntersecting), {rootMargin})
12+
observer.observe(ref.current)
13+
14+
return () => {
15+
if(ref.current == null) return
16+
observer.unobserve(ref.current)
17+
}
18+
19+
}, [ref.current, rootMargin])
20+
21+
22+
23+
return isVisible
24+
}

src/useScript.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import useAsync from "./useAsync";
2+
3+
export default function useScript(url: string): { loading: boolean; error: Error | undefined; }
4+
{
5+
return useAsync<undefined>(() => {
6+
const script = document.createElement("script")
7+
script.src = url
8+
script.async = true
9+
10+
return new Promise<any>((resolve, reject) => {
11+
script.addEventListener("load", resolve)
12+
script.addEventListener("error", reject)
13+
document.body.appendChild(script)
14+
})
15+
}, [url])
16+
}

src/useStorage.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export function useSessionStorage<T>(key: string, initialValue: T | (() => T)) {
99
}
1010

1111

12-
export function useStorage<T>(key: string, initialValue: T | (() => T), storageObject: Storage)
12+
export function useStorage<T>(key: string, initialValue: T | (() => T), storageObject: Storage): [T | undefined, React.Dispatch<React.SetStateAction<T | undefined>>, () => void]
1313
{
1414
const [value, setValue] = useState<T| undefined>(() => {
1515
const jsonValue = storageObject.getItem(key)

src/useWindowSize.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { useState } from "react"
2+
import useEventListener from "./useEventListener"
3+
4+
export type Size = {
5+
width: number
6+
height: number
7+
}
8+
9+
export default function useWindowSize() {
10+
const [windowSize, setWindowSize] = useState<Size>({
11+
width: window.innerWidth,
12+
height: window.innerHeight
13+
})
14+
15+
useEventListener("resize",async (e: Event) => {
16+
await setWindowSize({width: window.innerWidth, height: window.innerHeight})
17+
})
18+
19+
return windowSize
20+
}

0 commit comments

Comments
 (0)