Skip to content

Commit

Permalink
fix(hooks): hooks return stable functions, now use useCallback intern…
Browse files Browse the repository at this point in the history
…ally

issue: #22

hooks changed:
- useClickOutside
- useKeyStroke
- useLocalStorage
- useMediaStream
- useScreenShare
- useSessionStorage
- useStateHistory
- useToggle
- useUnMount
  • Loading branch information
heyitsarpit committed Dec 25, 2021
1 parent 47bad1c commit 55f4c4d
Show file tree
Hide file tree
Showing 9 changed files with 108 additions and 92 deletions.
16 changes: 10 additions & 6 deletions packages/core/useClickOutside/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { MaybeRef } from '@react-hooks-library/shared'
import { unRef } from '@react-hooks-library/shared'
import { useCallback } from 'react'

import { _window } from '../_ssr.config'
import { useEventListener } from '../useEventListener'
Expand Down Expand Up @@ -35,14 +36,17 @@ export function useClickOutside<
) {
const { event = 'pointerdown' } = options

const listener = (event: ClickOutsideEvents[E]) => {
const el = unRef(target)
if (!el) return
const listener = useCallback(
(event: ClickOutsideEvents[E]) => {
const el = unRef(target)
if (!el) return

if (el === event.target || event.composedPath().includes(el)) return
if (el === event.target || event.composedPath().includes(el)) return

handler(event)
}
handler(event)
},
[handler, target]
)

return useEventListener(_window, event, listener, { passive: true })
}
15 changes: 9 additions & 6 deletions packages/core/useKeyStroke/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { isString, MaybeRef } from '@react-hooks-library/shared'
import { MaybeRef } from '@react-hooks-library/shared'
import { useCallback } from 'react'

import { _window } from '../_ssr.config'
import { useEventListener } from '../useEventListener'
Expand Down Expand Up @@ -59,12 +60,14 @@ export function useKeyStroke(
code = false
} = options

const listener = (e: KeyboardEvent) => {
const eventKey = code ? e.code : e.key
const listener = useCallback(
(e: KeyboardEvent) => {
const eventKey = code ? e.code : e.key

if (isString(keys)) keys = [keys]
if (keys.includes(eventKey)) handler(e)
}
keys.includes(eventKey) && handler(e)
},
[code, handler, keys]
)

return useEventListener(target, eventName, listener, { passive })
}
Expand Down
26 changes: 13 additions & 13 deletions packages/core/useLocalStorage/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { isFunction } from '@react-hooks-library/shared'
import type { Dispatch, SetStateAction } from 'react'
import { useCallback } from 'react'
import { useState } from 'react'

import { useMount } from '../useMount'
Expand Down Expand Up @@ -33,7 +32,7 @@ export function useLocalStorage<T>(
key: string,
initialValue: T,
options?: UseLocalStorageOptions
): [T, Dispatch<SetStateAction<T>>] {
): [T, (value: T) => void] {
const [storedValue, setStoredValue] = useState(initialValue)
const { deserialize = JSON.parse, serialize = JSON.stringify } = options || {}

Expand All @@ -46,16 +45,17 @@ export function useLocalStorage<T>(
}
})

const setValue: Dispatch<SetStateAction<T>> = (value) => {
try {
const valueToStore = isFunction(value) ? value(storedValue) : value

setStoredValue(valueToStore)
localStorage.setItem(key, serialize(valueToStore))
} catch (error) {
console.error(error)
}
}
const setValue = useCallback(
(value: T) => {
try {
localStorage.setItem(key, serialize(value))
setStoredValue(value)
} catch (error) {
console.error(error)
}
},
[key, serialize]
)

return [storedValue, setValue]
}
57 changes: 30 additions & 27 deletions packages/core/useMediaStream/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useEffect, useRef, useState } from 'react'
import { useCallback, useEffect, useRef, useState } from 'react'

import { _navigator } from '../_ssr.config'
import { useIsSupported } from '../useIsSupported'
Expand Down Expand Up @@ -50,16 +50,19 @@ export function useMediaStream(options: UseMediaStreamOptions = {}) {
const [isAudioMuted, setAudioMuted] = useState(false)
const [isVideoMuted, setVideoMuted] = useState(false)

function getDeviceOptions(device: string | undefined | false | 'none') {
if (device === 'none' || device === false) return false
if (device === null) return true
const getDeviceOptions = useCallback(
(device: string | undefined | false | 'none') => {
if (device === 'none' || device === false) return false
if (device === null) return true

return {
deviceId: device
}
}
return {
deviceId: device
}
},
[]
)

async function play() {
const play = useCallback(async () => {
if (!isSupported || stream.current) return

stream.current =
Expand All @@ -70,48 +73,48 @@ export function useMediaStream(options: UseMediaStreamOptions = {}) {

setPlaying(true)
return stream.current
}
}, [audioDeviceId, getDeviceOptions, isSupported, videoDeviceId])

async function stop() {
const stop = useCallback(() => {
setPlaying(false)
stream.current?.getTracks().forEach((t) => t.stop())
stream.current = null
}
}, [])

async function restart() {
const restart = useCallback(async () => {
stop()
return await play()
}
}, [play, stop])

function muteAudio() {
const muteAudio = useCallback(() => {
setAudioMuted(true)
stream.current?.getAudioTracks().forEach((t) => (t.enabled = false))
}
}, [])

function unMuteAudio() {
const unMuteAudio = useCallback(() => {
setAudioMuted(false)
stream.current?.getAudioTracks().forEach((t) => (t.enabled = true))
}
}, [])

function muteVideo() {
const muteVideo = useCallback(() => {
setVideoMuted(true)
stream.current?.getVideoTracks().forEach((t) => (t.enabled = false))
}
}, [])

function unMuteVideo() {
const unMuteVideo = useCallback(() => {
setVideoMuted(false)
stream.current?.getVideoTracks().forEach((t) => (t.enabled = true))
}
}, [])

function pause() {
const pause = useCallback(() => {
muteAudio()
muteVideo()
}
}, [muteAudio, muteVideo])

function resume() {
const resume = useCallback(() => {
unMuteAudio()
unMuteVideo()
}
}, [unMuteAudio, unMuteVideo])

useEffect(() => {
if (!ref.current) return
Expand All @@ -121,7 +124,7 @@ export function useMediaStream(options: UseMediaStreamOptions = {}) {

useEffect(() => {
if (autoSwitch && stream.current) restart()
}, [videoDeviceId, audioDeviceId, autoSwitch])
}, [videoDeviceId, audioDeviceId, autoSwitch, restart])

return {
isSupported,
Expand Down
12 changes: 6 additions & 6 deletions packages/core/useScreenShare/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useEffect, useRef, useState } from 'react'
import { useCallback, useEffect, useRef, useState } from 'react'

import { _navigator } from '../_ssr.config'
import { useIsSupported } from '../useIsSupported'
Expand Down Expand Up @@ -36,7 +36,7 @@ export function useScreenShare(options: UseScreenShareOptions = {}) {

const [isPlaying, setPlaying] = useState(false)

async function play() {
const play = useCallback(async () => {
if (!isSupported || !ref.current) return

stream.current =
Expand All @@ -48,13 +48,13 @@ export function useScreenShare(options: UseScreenShareOptions = {}) {
setPlaying(true)

return stream.current
}
}, [audio, isSupported, video])

async function stop() {
const stop = useCallback(() => {
stream.current?.getTracks().forEach((t) => t.stop())
stream.current = null
setPlaying(false)
}
}, [])

useEffect(() => {
if (!ref.current) return
Expand All @@ -63,7 +63,7 @@ export function useScreenShare(options: UseScreenShareOptions = {}) {

// Handle os native stop screen sharing buttons
stream.current?.getVideoTracks()[0].addEventListener('ended', stop)
}, [isPlaying])
}, [isPlaying, stop])

return {
isSupported,
Expand Down
25 changes: 13 additions & 12 deletions packages/core/useSessionStorage/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { isFunction } from '@react-hooks-library/shared'
import type { Dispatch, SetStateAction } from 'react'
import { Dispatch, SetStateAction, useCallback } from 'react'
import { useState } from 'react'

import { useMount } from '../useMount'
Expand Down Expand Up @@ -33,7 +33,7 @@ export function useSessionStorage<T>(
key: string,
initialValue: T,
options?: UseSessionStorageOptions
): [T, Dispatch<SetStateAction<T>>] {
): [T, (value: T) => void] {
const [storedValue, setStoredValue] = useState(initialValue)
const { deserialize = JSON.parse, serialize = JSON.stringify } = options || {}

Expand All @@ -46,16 +46,17 @@ export function useSessionStorage<T>(
}
})

const setValue: Dispatch<SetStateAction<T>> = (value) => {
try {
const valueToStore = isFunction(value) ? value(storedValue) : value

setStoredValue(valueToStore)
sessionStorage.setItem(key, serialize(valueToStore))
} catch (error) {
console.error(error)
}
}
const setValue = useCallback(
(value: T) => {
try {
setStoredValue(value)
sessionStorage.setItem(key, serialize(value))
} catch (error) {
console.error(error)
}
},
[key, serialize]
)

return [storedValue, setValue]
}
37 changes: 20 additions & 17 deletions packages/core/useStateHistory/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { isFunction } from '@react-hooks-library/shared'
import { useRef, useState } from 'react'
import { useCallback, useRef, useState } from 'react'

type UseStateHistoryOptions = {
/**
Expand Down Expand Up @@ -34,27 +34,30 @@ export function useStateHistory<T>(
const redoHistory = useRef<T[]>([])
const redoAllowed = useRef(false)

const push = (value: T) => {
if (actionHistory.current.length < maxHistory) {
actionHistory.current.push(value)
} else {
actionHistory.current = [...actionHistory.current.slice(1), value]
lastSaved.current = actionHistory.current[0]
}
const push = useCallback(
(value: T) => {
if (actionHistory.current.length < maxHistory) {
actionHistory.current.push(value)
} else {
actionHistory.current = [...actionHistory.current.slice(1), value]
lastSaved.current = actionHistory.current[0]
}

redoAllowed.current = false
setState(value)
}
redoAllowed.current = false
setState(value)
},
[maxHistory]
)

const redo = () => {
const redo = useCallback(() => {
if (!(redoHistory.current.length && redoAllowed.current)) return

const lastUndoState = redoHistory.current.pop()
lastUndoState && push(lastUndoState)
redoAllowed.current = true
}
}, [push])

const undo = () => {
const undo = useCallback(() => {
if (actionHistory.current.length < 1) return

const lastState = actionHistory.current.pop()
Expand All @@ -64,12 +67,12 @@ export function useStateHistory<T>(
prev ? setState(prev) : setState(lastSaved.current)
rerender({})
redoAllowed.current = true
}
}, [rerender])

const reset = () => {
const reset = useCallback(() => {
setState(actionHistory.current[0])
actionHistory.current = [actionHistory.current[0]]
}
}, [])

return {
state,
Expand Down
10 changes: 6 additions & 4 deletions packages/core/useToggle/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useState } from 'react'
import { useCallback, useState } from 'react'

/**
* A state toggle hook
Expand All @@ -11,9 +11,11 @@ import { useState } from 'react'
export function useToggle(defaultValue = false) {
const [bool, setBool] = useState(defaultValue)

const toggle = () => setBool((s) => !s)
const setTrue = () => setBool(true)
const setFalse = () => setBool(false)
const toggle = useCallback(() => setBool((s) => !s), [])

const setTrue = useCallback(() => setBool(true), [])

const setFalse = useCallback(() => setBool(false), [])

return { bool, toggle, setTrue, setFalse }
}
2 changes: 1 addition & 1 deletion packages/core/useUnMount/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ import { useEffect } from 'react'
export function useUnMount(func: Fn) {
useEffect(() => {
return func
}, [])
}, [func])
}

0 comments on commit 55f4c4d

Please sign in to comment.