Skip to content

Commit 7320252

Browse files
author
João Dias
committed
docs(hooks): improved jsdoc examples
1 parent 38eca43 commit 7320252

21 files changed

+157
-50
lines changed

docs/docs/hooks/use-live-ref.mdx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@ title: useLifecycle
33
---
44
Creates a `React.RefObject` that is constantly updated with the incoming value.
55

6+
React's useRef hook, primarily used for accessing DOM nodes or React elements, has another valuable application: stabilizing references.
7+
8+
By wrapping volatile references in a stable container, useRef allows developers to grant dependencies immunity to change, which is particularly useful when you don't want hooks to trigger on every variable change.
9+
10+
This technique is especially beneficial when working with hooks like useEffect. For instance, when dealing with side effects that depend on changing variables, using useRef can prevent unnecessary re-evaluations and ensure more consistent behavior. A custom hook like useLiveRef can be implemented to provide a stable reference to changing values, offering finer control over when hooks are re-evaluated without compromising the integrity of dependency arrays or ESLint rules.
11+
612
## API
713

814
```typescript

docs/docs/hooks/use-merge-refs.mdx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
---
22
title: useMergeRefs
33
---
4-
Returns a function that receives the element and assign the value to the given React refs.
4+
The `useMergeRefs` hook is designed to combine multiple React refs into a single callback ref.
5+
6+
This is particularly useful when you need to apply multiple refs to a single element, such as when working with both internal component logic and external ref forwarding.
7+
8+
By merging refs, you can maintain the functionality of each individual ref while avoiding conflicts or overrides that might occur when attempting to assign multiple refs directly.
9+
10+
This hook enhances component flexibility and reusability, allowing developers to easily integrate both component-specific refs and externally provided refs in a clean, efficient manner.
511

612
## API
713

src/functions/events/custom-events/use-custom-event-listener.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,13 @@ import { getElement } from "./get-element";
1111
* A custom hook that listens to a custom event and auto-cleans itself on unmount.
1212
*
1313
* @example
14+
* ```tsx
15+
* import { useCustomEventListener } from "@feedzai/js-utilities/hooks";
16+
* ...
1417
* useCustomEventListener('a-custom-event-name', data => {
1518
* doSomethingWithData( data );
1619
* });
20+
* ```
1721
*/
1822
export function useCustomEventListener<GenericType>(
1923
eventName: string,

src/hooks/use-auto-id.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,14 @@ function generateIncrementalId() {
3030
* component mounts. Users may need to supply their own ID if they need
3131
* consistent values for SSR.
3232
*
33-
* @example
33+
* Note: The id generating mechanism uses `useId` under the hook, if on React 18+.
3434
*
35+
* @example
36+
* ```tsx
37+
* import { useAutoId } from '@feedzai/js-utilities/hooks';
38+
* ...
3539
* // Generating an id (no pre-defined id and no prefix)
36-
* const id1 = useAutoId(); // will return, for example, "0"
40+
* const id1 = useAutoId(); // will return, for example, "0" (or :r0: if on React 18+)
3741
*
3842
* // Using a pre-defined id (no prefix)
3943
* const id2 = useAutoId("8e88aa2e-e6a8") // will return "8e88aa2e-e6a8"
@@ -43,7 +47,7 @@ function generateIncrementalId() {
4347
*
4448
* // Using a prefix with a pre-defined id
4549
* const id4 = useAutoId("6949d175", "fdz-js-checkbox") // will return "fdz-js-checkbox--6949d175"
46-
*
50+
*``
4751
* @param {string | null | undefined} customId - You can pass an previously defined value
4852
* and that value will be used as the value of the returned id.
4953
* @param {string | undefined} prefix - If necessary, you can prepend a generated id with a prefix.

src/hooks/use-click-outside.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,15 @@ import React, { useEffect } from "react";
1313
* the callback function.
1414
*
1515
* @example
16+
* ```tsx
17+
* import { useClickOutside } from '@feedzai/js-utilities/hooks';
18+
* ...
1619
* useClickOutside(
17-
DROPDROWN_REF,
18-
() => closeDropdown(),
19-
shouldClose,
20-
);
20+
* DROPDROWN_REF,
21+
* () => closeDropdown(),
22+
* shouldClose,
23+
* );
24+
* ```
2125
*/
2226
export function useClickOutside<GenericElement extends Element = HTMLElement>(
2327
ref: React.Ref<GenericElement>,
@@ -27,7 +31,7 @@ export function useClickOutside<GenericElement extends Element = HTMLElement>(
2731
useEffect(
2832
() => {
2933
const listener = <GenericEvent extends Event>(event: GenericEvent) => {
30-
// @ts-ignore Do nothing if clicking ref's element or descendent elements
34+
// @ts-expect-error Do nothing if clicking ref's element or descendent elements
3135
if (isNil(ref) || isNil(ref["current"]) || ref["current"].contains(event.target)) {
3236
return;
3337
}

src/hooks/use-constant.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ import { useRef } from "react";
1212
* See {@link https://reactjs.org/docs/hooks-faq.html#how-to-create-expensive-objects-lazily this FAQ on React's own homepage}
1313
*
1414
* @example
15+
* ```tsx
16+
* import { useConstant } from '@feedzai/js-utilities/hooks';
17+
* ...
1518
* // Calling the translateText function once
1619
* const messages = useConstant(() => {
1720
* return {
@@ -22,9 +25,13 @@ import { useRef } from "react";
2225
*
2326
* // Consuming its unmodified value later on
2427
* <p>{messages.description}</p>
28+
* ```
2529
*
2630
* @example
27-
* const configs = useConstant(() => {
31+
* ```tsx
32+
* import { useConstant } from '@feedzai/js-utilities/hooks';
33+
* ...
34+
* const configs = useConstant(() => {
2835
* const hasIcon = !isEmpty(icon);
2936
* const iconClass = classNames("some-css-class", getIconClass(hasIcon, kind, icon));
3037
*
@@ -36,6 +43,7 @@ import { useRef } from "react";
3643
*
3744
* // Consuming its unmodified value later on
3845
* <p>{configs.hasIcon}</p>
46+
* ```
3947
*/
4048
export function useConstant<FunctionReturnType>(fn: () => FunctionReturnType): FunctionReturnType {
4149
const ref = useRef<{ instance: FunctionReturnType }>();

src/hooks/use-container-query/index.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ import {
2323
* the size of a containing element rather than the size of the browser viewport.
2424
*
2525
* @example
26-
*
26+
* ```jsx
27+
* import { useContainerQuery } from "@feedzai/js-utilities/hooks";
28+
* ...
2729
* const BREAKPOINTS = {
2830
* "xs": [0, 960],
2931
* "sm": [961, 1200],
@@ -42,7 +44,7 @@ import {
4244
* </div>
4345
* );
4446
* }
45-
*
47+
* ```
4648
*/
4749
export function useContainerQuery<GenericType extends HTMLElement>({
4850
breakpoints = DEFAULT_BREAKPOINTS,

src/hooks/use-controlled-state/index.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,18 @@ import { SetState } from "./types";
1212
* Check if a component is controlled or uncontrolled and returns the correct
1313
* state value and setter accordingly. If the component state is controlled by
1414
* the app, the setter is an empty function.
15+
*
16+
* @example
17+
* ```tsx
18+
* import { useControlledState } from '@feedzai/js-utilities/hooks';
19+
* ...
20+
* function Tabs(props) {
21+
* // The selected index can be defined by the Tabs internal state or a parent.
22+
* const [selectedIndex, setSelectedIndex] = useControlledState(
23+
* props.defaultIndex ?? DEFAULT_INITIAL_TAB_INDEX,
24+
* props.controlledIndex,
25+
* );
26+
* ```
1527
*/
1628
export function useControlledState<StateType>(
1729
defaultState: StateType | (() => StateType),

src/hooks/use-copy-to-clipboard.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,12 @@ function writeToClipboard(value: string) {
3232
* Copy text to a user's clipboard.
3333
*
3434
* @example
35-
* ```
36-
* import { useCopyToClipboard } from "@feedzai/js-utilities";
35+
* ```tsx
36+
* import { useCopyToClipboard } from "@feedzai/js-utilities/hooks";
3737
* ...
3838
* function Demo() {
3939
* const [text, setText] = useState('');
40-
* const { value, error, copyToClipboard } = useCopyToClipboard();
40+
* const { value, error, copyToClipboard } = useCopyToClipboard();
4141
*
4242
* return (
4343
* <div>

src/hooks/use-effect-once.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ import { EffectCallback, useEffect } from "react";
1111
* Runs an effect only once.
1212
*
1313
* @example
14-
* ```
15-
* import {useEffectOnce} from '@feedzai/js-utilities';
14+
* ```tsx
15+
* import {useEffectOnce} from '@feedzai/js-utilities/hooks';
1616
*
1717
* useEffectOnce(() => {
1818
* console.log('This runs only one time, when mounting');

src/hooks/use-lifecycle.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ import { isFunction } from "../index";
1010
* React lifecycle hook that calls mount and unmount callbacks, when component is mounted and un-mounted, respectively.
1111
*
1212
* @example
13-
* ```
14-
* import { useLifecycle } from "@feedzai/js-utilities";
13+
* ```tsx
14+
* import { useLifecycle } from "@feedzai/js-utilities/hooks";
1515
* ...
1616
* useLifecycle(
1717
* () => console.log('runs on mount'),

src/hooks/use-live-ref.ts

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,29 @@
66
import { MutableRefObject, useRef, useLayoutEffect } from "react";
77

88
/**
9-
* Creates a `React.RefObject` that is constantly updated with the incoming
10-
* value.
9+
* Creates a `React.RefObject` that is constantly updated with the incoming value.
10+
*
11+
* React's useRef hook, primarily used for accessing DOM nodes or React elements, has another
12+
* valuable application: stabilizing references.
13+
*
14+
* By wrapping volatile references in a stable container, useRef allows developers to grant dependencies
15+
* immunity to change, which is particularly useful when you don't want hooks to trigger on every variable change.
16+
*
17+
* This technique is especially beneficial when working with hooks like useEffect. For instance, when dealing with
18+
* side effects that depend on changing variables, using useRef can prevent unnecessary re-evaluations and ensure
19+
* more consistent behavior. A custom hook like useLiveRef can be implemented to provide a stable reference to
20+
* changing values, offering finer control over when hooks are re-evaluated without compromising the integrity of
21+
* dependency arrays or ESLint rules.
22+
*
1123
* @example
24+
*
25+
* ```tsx
26+
* import { useLiveRef } from '@feedzai/js-utilities/hooks';
27+
* ...
1228
* function Component({ prop }) {
1329
* const propRef = useLiveRef(prop);
1430
* }
31+
* ```
1532
*/
1633
export function useLiveRef<T>(value: T): MutableRefObject<T> {
1734
const ref = useRef(value);

src/hooks/use-merge-refs.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,20 @@ export function mergeRefs<Generic = HTMLElement>(
4444
}
4545

4646
/**
47-
* Returns a function that receives the element and assign the value to the given React refs.
47+
* The useMergeRefs hook is designed to combine multiple React refs into a single callback ref.
4848
*
49-
* @example
49+
* This is particularly useful when you need to apply multiple refs to a single element, such as when working with
50+
* both internal component logic and external ref forwarding. By merging refs, you can maintain the functionality of
51+
* each individual ref while avoiding conflicts or overrides that might occur when attempting to assign multiple
52+
* refs directly.
5053
*
51-
* ```
54+
* This hook enhances component flexibility and reusability, allowing developers to easily integrate both
55+
* component-specific refs and externally provided refs in a clean, efficient manner.
56+
*
57+
* @example
58+
* ```tsx
59+
* import { useMergeRefs } from '@feedzai/js-utilities/hooks';
60+
* ...
5261
* // a div with multiple refs
5362
* function Example({ ref, ...props }) {
5463
* const internalRef = React.useRef();

src/hooks/use-mount.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { useEffectOnce } from "./use-effect-once";
1010
*
1111
* @example
1212
* ```
13-
* import { useMount } from "@feedzai/js-utilities";
13+
* import { useMount } from "@feedzai/js-utilities/hooks";
1414
* ...
1515
* useMount(() => {
1616
* console.log("the component has mounted");

src/hooks/use-mounted-state.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { useCallback, useEffect, useRef } from "react";
1111
*
1212
* @example
1313
* ```
14-
* import { useMountedState } from "@feedzai/js-utilities";
14+
* import { useMountedState } from "@feedzai/js-utilities/hooks";
1515
* ...
1616
* const isMounted = useMountedState();
1717
*

src/hooks/use-network-state/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ function getConnectionState(previousState?: UseNetworkState): UseNetworkState {
3636
* Tracks the state of browser's network connection.
3737
*
3838
* @example
39+
* ```tsx
40+
* import { useNetworkState } from '@feedzai/js-utilities/hooks';
41+
* ...
3942
* const onlineState = useNetworkState();
4043
*
4144
* return (
@@ -44,6 +47,7 @@ function getConnectionState(previousState?: UseNetworkState): UseNetworkState {
4447
* <pre>{JSON.stringify(onlineState, null, 2)}</pre>
4548
* </div>
4649
* );
50+
* ```
4751
*/
4852
export function useNetworkState(initialState?: UseNetworkState): UseNetworkState {
4953
const [state, setState] = useState(initialState ?? getConnectionState);

src/hooks/use-page-visibility/index.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ import { PageVisibilityCallback } from "./types";
2323
* d) A site wants to switch off sounds when a device is in standby mode (user pushes power button to turn screen off)
2424
*
2525
* @example
26+
* ```tsx
27+
* import { usePageVisibility } from '@feedzai/js-utilities/hooks';
28+
* ...
2629
* // When the user changes tabs, save the written note draft
2730
* usePageVisibility((isVisible) => {
2831
* if (!isVisible) {
@@ -36,9 +39,7 @@ import { PageVisibilityCallback } from "./types";
3639
* saveNoteDraft();
3740
* }
3841
* }, 2000);
39-
*
40-
* @param {PageVisibilityCallback} handlerCallback Callback function to run when page visibility changes. A boolean value (indicating whether the page is visible or not) will be passed as an argument to this function.
41-
* @param {number} [delay] Number of milliseconds to wait before responding to page visibility change
42+
* ```
4243
*/
4344
export function usePageVisibility(handlerCallback: PageVisibilityCallback, delay?: number): void {
4445
const { current: BROWSER_COMPATIBILITY } = useRef(getBrowserCompatibility());

src/hooks/use-permission/index.ts

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -13,26 +13,22 @@ import { UsePermissionState } from "./types";
1313
* - Automatically updates on permission state change.
1414
*
1515
* @example
16+
* ```tsx
17+
* import { usePermission } from '@feedzai/js-utilities/hooks';
18+
* ...
1619
* const status = usePermission({ name: 'notifications' });
17-
18-
return (
19-
<div>
20-
<div>
21-
Notifications status: <code>{status}</code>
22-
</div>
23-
<div>
24-
{status === 'prompt' && (
25-
<button
26-
onClick={() => {
27-
28-
Notification.requestPermission();
29-
}}>
30-
Request notifications permission
31-
</button>
32-
)}
33-
</div>
34-
</div>
35-
);
20+
*
21+
* return (
22+
* <>
23+
* <p>Notifications status: <code>{status}</code></p>
24+
* {status === 'prompt' && (
25+
* <button type="button" onClick={() => Notification.requestPermission()}>
26+
* Request notifications permission
27+
* </button>
28+
* )}
29+
* </>
30+
* );
31+
* ```
3632
*
3733
* @param descriptor Permission request descriptor that passed to `navigator.permissions.query`
3834
*/

src/hooks/use-previous.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,23 @@ import { useEffect, useRef } from "react";
88
/**
99
* React state hook that returns the previous state as described in the React hooks FAQ.
1010
* {@link https://reactjs.org/docs/hooks-faq.html#how-to-get-the-previous-props-or-state}
11+
*
12+
* @example
13+
* ```tsx
14+
* import { usePrevious } from '@feedzai/js-utilities/hooks';
15+
* ...
16+
* function Component() {
17+
* const [value, setValue] = useState(0);
18+
* const previousValue = usePrevious(value);
19+
*
20+
* return (
21+
* <div>
22+
* <span>{previousValue}</span>
23+
* <button onClick={() => setValue((prev) => prev + 1)}>Increment</button>
24+
* </div>
25+
* );
26+
* }
27+
* ```
1128
*/
1229
export function usePrevious<GenericType>(state: GenericType): GenericType | undefined {
1330
const ref = useRef<GenericType>();

0 commit comments

Comments
 (0)