README
Hooks for React
A Set of Must use Hooks necessary for daily work with React
Table of contents
State
useSuperState
Use a state with super powers.
This hook is like a combination of useState
, useMemo
and useRef
hooks at once.
Returns a stateful value, and a function to update it + a ref to the state value.
Definition
<S>(factory: S | ((prev: S) => S), deps?: DependencyList): [S, Dispatch<SetStateAction<S>>, MutableRefObject<S>]
Usage
You can use it as you normally do with the useState
hook.
const [state, setState, stateRef] = useSuperState(/* Initial state */ 0)
const [state, setState, stateRef] = useSuperState(/* Initial state creator - run only once */ () => 0)
Or you can pass a factory function and a list of dependencies as you would do with the useMemo
hook.
The state will be changed either by using setState
or from outside when the list of dependencies changes.
Note: You have access to the previous state by the parameter passed to the factory function.
const [state, setState, stateRef] = useSuperState(
// State factory - run if the dependency list changed
prevState => (prevState || 0) + props.count,
// Dependency list
[props.count]
)
You can also change the state without triggering a new rendering, by changing the stateRef
value..
stateRef.current = newValue
useBindState
Bind a state to an outside value.
When the outside value changes, the state will be updated with the new value.
Returns a stateful value and function to update it + ref to the state value.
Definition
<S>(value: S): [S, Dispatch<SetStateAction<S>>, MutableRefObject<S>]
usage
The outsideValue
will create the initial state, and will also update the state when it changes.
const [state, setState, stateRef] = useBindState(outsideValue)
Callback
useSameCallback
This hook is just like the useCallback
hook with an empty array. This means that the callback will not change during the life of the component.
Returns a reference to the initial passed callback.
Definition
<T extends (...args: any[]) => any>(callback: T): T
usage
const onClick = useSameCallback(() => console.log(exampleRef.current))
Ref
useSuperRef
Use a ref with super powers.
This hook is like a combination of useMemo
and useRef
hooks at once.
Returns a value, and a ref to the value.
Definition
<V>(factory: V | ((prev: V) => V), deps?: DependencyList): [V, MutableRefObject<V>]
Usage
You can use it as you normally do with the useRef
hook.
const [value, valueRef] = useSuperRef()
const [value, valueRef] = useSuperRef(/* Initial value */ 0)
Or you can pass an initializer function.
const [value, valueRef] = useSuperRef(/* Initial value creator - only runs once */ () => 0)
Or you can pass a factory function and a list of dependencies as you would do with the useMemo
hook.
The value will be changed either by using useRef.current
or from outside when the list of dependencies changes.
Note: You have access to the previous value by the parameter passed to the factory function.
const [value, valueRef] = useSuperRef(
// ref value factory - run if the dependency list changed
prevValue => (prevValue || 0) + props.count,
// Dependency list
[props.count]
)
useBindRef
Bind a ref to an outside value.
When the outside value changes, the ref value will be updated to the new value.
Returns the ref object.
Definition
<V>(value: V): MutableRefObject<V>
usage
The outsideValue
value will be the initial ref value and will also update the ref value when it changes.
const myRef = useBindRef(outsideValue)
useInnerRef
Convert forwardedRef
to a new regular React
ref object.
Useful when using forwardedRef
and you want to use the ref as a regular ref within the component as well.
Returns the ref object.
Definition
<T>(ref: ForwardedRef<T>): MutableRefObject<T>
usage
const ExampleComp = forwardedRef((props, ref)=> {
const innerRef = useInnerRef(ref)
useEffect(
()=> console.log(innerRef.current),
[innerRef.current]
)
return <div ref={innerRef}></div>
})
Lifecycles
useInitial
Use the initial value returned by the create function, which is invoked when the component initialized.
This hook is basically a substitute for the behavior of the constructor in the class components.
Returns the initial value.
Definition
<V>(create: () => V) => V
usage
const id = useInitial(() => Math.random())
useRun
This hook will run immediately if the dependency list changes.
The main difference between this hook and the React
lifecycles hooks is: this hook is called immediately but the useEffect
hook for example run after processing the component.
Returns an isFirstRun indicator.
Definition
(callback: () => void, deps: DependencyList): { isFirstRun: boolean, isFirstRunRef: MutableRefObject<boolean> }
usage
const ExampleComp = props => {
const myRef = useRef(5)
useRun(() => myRef.current += props.count, [props.count])
return myRef.current > 10 && <div>Hello World!</div>
}
You also have additional data returns that can be useful in some cases.
const { isFirstRun, isFirstRunRef } = useRun(() => console.log(`Dependencies change`), [...someDeps])
useAsyncEffect
This hook is a modified version of React
useEffect
hook that adds a nice support for async callback effect.
You can achieve the same cleanup behavior as the native useEffect
by accessing the effect argument and passing to it a callback. Note: You should call it above any async operation (AKA before the await
keyword)
Note: If you don't pass an dependency list, the effect will rerun after every completed render.
Note: Use useLayoutAsyncEffect
for the layout effect version.
Definition
(effect: (onCleanup: (execute: () => void | Promise<void>) => void) => Promise<void>, deps?: DependencyList): void
usage
useAsyncEffect(
async () => {
const user = await myApi.get('./user')
setData(user)
},
[]
)
With cleanup:
useAsyncEffect(
async (onCleanup)=> {
const ac = new AbortController()
// Call onCleanup above any async operation
onCleanup(
// cleanup callback
() => ac.abort()
)
const res = await fetch('./my-api', { signal: ac.signal })
const data = await res.json()
setData(data)
// onCleanup(() => ac.abort()) -> This is NOT OK!
},
[someDep]
)
useIf
Run a effect callback when the first parameter is truthy.
Note: The Effect Callback can have a React
useEffect
Callback signature, or a useAsyncEffect
Callback signature.
Note: Use useLayoutIf
for the layout effect version.
Returns the truthiness of the condition passed in the first parameter.
Definition
(condition: unknown, callback: EffectCallback): boolean
usage
Except a React
useEffect
callback.
useIf(someValue === otherValue, () => {
console.log(`It is equal`)
// Cleanup
return () => console.log(`Cleaned up`)
})
useAsyncEffect
callback also will work.
useIf(someValue === otherValue, async onCleanup => {
onCleanup(() => console.log(`Cleaned up`)) // Always put it above any async operation.
const data = await api.send(`It is equal`)
console.log(data)
})
And it will return the truthiness of the condition.
const conditionPass = useIf(someValue === otherValue, () => console.log(`It is equal`))
useMount
Run a callback when the component is mounted.
Note: The Effect Callback can have a React
useEffect
Callback signature, or a useAsyncEffect
Callback signature.
Note: Use useLayoutMount
for the layout effect version.
Definition
(callback: EffectCallback): void
usage
Except a React
useEffect
callback.
useMount(() => {
console.log(`It is equal`)
// Cleanup
return () => console.log(`Cleaned up`)
})
Callback signature for useAsyncEffect
should also will work.
useMount(async onCleanup => {
onCleanup(() => console.log(`Cleaned up`)) // Always put it above any async operation.
const data = await api.send(`It is equal`)
console.log(data)
})
useIsMount
Get to know the component current mounted state.
Returns a boolean and a ref to the boolean.
Definition
(): [boolean, MutableRefObject<boolean>]
usage
const [isMount, isMountRef] = useIsMount()
useUnmount
Run a callback when the component is unmounted.
Returns the callback that get passed.
Definition
<C extends (()=> void | Promise<void>>)>(callback: C): C
usage
useUnmount(() => console.log(`Component unmounted`))
useUnmount(() => someSubscription.unsubscribe())
useRender
Give you a option to force the component to be render.
Returns a render function that can be invoked to render the component when you need so.
Definition
(): () => void
usage
const render = useRender()
useEffect(() => render(), [...someDeps]) // the component will render when the deps get changed.
Dom
useClassName
Join lists of dom element className to be one className string, and memoized it depending on dependency list.
Returns a string represents the combination of all className in the array list.
Definition
(factory: () => Array<string>, deps: DependencyList): string
usage
const myClassName = useClassName(
// Define a factory that returns array of classNames
() => [
`flex black`,
someCondition && `some-class other-class`,
secondCondition ? `new-class-list`: ``
],
// List of dependencies go here
[someCondition, secondCondition]
)
<div className={myClassName}>Hello world</div>
useStyle
Create style and memoized it depending on dependency list.
Returns the created style object, ready for use as a property of html element.
Definition
(factory: () => CSSProperties, deps: DependencyList): CSSProperties
usage
const myStyle = useStyle(
// Define a Factory that returns style object
() => ({
backgroundColor: someCondition && `black`,
color: someCondition ? `white`: `black`
}),
// List of dependencies go here
[someCondition]
)
<div style={myStyle}>Hello world</div>
useHover
Get a sense when a element dom get hovered.
Note: You can disabled the hook functionality by passing false
to the enabled option.
Note: If you don't pass ref to the element by using the ref option, an ref will be created for you.
Returns a boolean represents the truthiness of the element hover state, and a ref to the element.
Definition
<T extends HTMLElement>({ ref, enabled }?: { ref?: MutableRefObject<T>, enabled?: boolean }): [boolean, MutableRefObject<T>]
usage
const [isHover, btnRef] = useHover()
<button ref={btnRef}>Hover Me</button>
You have also some options you can pass to the hook.
Here is an example of using pre created ref.
const btnRef = useRef()
const [isHover] = useHover({ ref: btnRef })
Also you can disabled the hover functionality and logic if you don`t need it right now.
Note: The default value for the enabled option is true
.
const isMobile = true
const [isHover, btnRef] = useHover({ enabled: !isMobile })
Timer
useTimeout
Use a callback on amount of time after the dependency list changes.
Note: If you don't pass an dependency list, the effect will stop and rerun after every completed render.
Note: This hook used requestAnimationFrame
behind the scenes, for performance reason.
Note: Use useLayoutTimeout
for the layout effect version.
Returns a ref to the current result of requestAnimationFrame
call.
Definition
(callback: () => void, ms?: number, deps?: DependencyList): MutableRefObject<number>
usage
const handleRef = useTimeout(
/* callback */
() => console.log(`DependencyList changes`),
/* milliseconds */
1000,
/* Dependency List */
[...someDeps]
)
And you can cancel the requestAnimationFrame
like so.
cancelAnimationFrame(handleRef.current)
useInterval
Restart a interval on amount of time after the dependency list changes.
Note: If you don't pass an dependency list, the effect will rerun after every completed render.
Note: This hook used requestAnimationFrame
behind the scenes, for performance reason.
Note: Use useLayoutInterval
for the layout effect version.
Returns a ref to the current result of requestAnimationFrame
call.
Definition
(callback: () => void, ms?: number, deps?: DependencyList): MutableRefObject<number>
usage
const handleRef = useInterval(
/* callback */
() => console.log(`DependencyList changes`),
/* milliseconds */
1000,
/* DependencyList */
[...someDeps]
)
And you can cancel the requestAnimationFrame
like so.
cancelAnimationFrame(handleRef.current)
Logger
useLog
Log when parameters changed.
Returns a list holding the parameters that get passed.
Definition
<T>(...params: T): T
usage
useLog(props.count, props.className)
// Log to the console a list with the current value of the parameters
If you pass only one object parameter, it will compares the object deeply for tracking a changes and log the new object to the console.
useLog({ count: props.count, myState: state })
// Log the object when one of the properties changed.