Skip to content

Commit

Permalink
Docs/add use event callback documentation (#481)
Browse files Browse the repository at this point in the history
* πŸ“ Add docs for `useEventCallback`

* πŸ“ Add demo for `useEventCallback`

* βœ… Add unit tests for `useEventCallback`

* ✏️ Remove useless comment in useLocalStorage's demo

* πŸ”– Add changeset

* πŸ“ Update README
  • Loading branch information
juliencrn committed Feb 9, 2024
1 parent bc3f967 commit 7d74e09
Show file tree
Hide file tree
Showing 8 changed files with 65 additions and 7 deletions.
5 changes: 5 additions & 0 deletions .changeset/dry-deers-listen.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"usehooks-ts": patch
---

Release documentation for `useEventCallback`
4 changes: 1 addition & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,12 @@
- [`useDebounceCallback()`](https://usehooks-ts.com/react-hook/use-debounce-callback)
- [`useDebounceValue()`](https://usehooks-ts.com/react-hook/use-debounce-value)
- [`useDocumentTitle()`](https://usehooks-ts.com/react-hook/use-document-title)
- [`useEffectOnce()`](https://usehooks-ts.com/react-hook/use-effect-once)
- [`useEventCallback()`](https://usehooks-ts.com/react-hook/use-event-callback)
- [`useEventListener()`](https://usehooks-ts.com/react-hook/use-event-listener)
- [`useHover()`](https://usehooks-ts.com/react-hook/use-hover)
- [`useIntersectionObserver()`](https://usehooks-ts.com/react-hook/use-intersection-observer)
- [`useInterval()`](https://usehooks-ts.com/react-hook/use-interval)
- [`useIsClient()`](https://usehooks-ts.com/react-hook/use-is-client)
- [`useIsFirstRender()`](https://usehooks-ts.com/react-hook/use-is-first-render)
- [`useIsMounted()`](https://usehooks-ts.com/react-hook/use-is-mounted)
- [`useIsomorphicLayoutEffect()`](https://usehooks-ts.com/react-hook/use-isomorphic-layout-effect)
- [`useLocalStorage()`](https://usehooks-ts.com/react-hook/use-local-storage)
Expand All @@ -68,7 +67,6 @@
- [`useTimeout()`](https://usehooks-ts.com/react-hook/use-timeout)
- [`useToggle()`](https://usehooks-ts.com/react-hook/use-toggle)
- [`useUnmount()`](https://usehooks-ts.com/react-hook/use-unmount)
- [`useUpdateEffect()`](https://usehooks-ts.com/react-hook/use-update-effect)
- [`useWindowSize()`](https://usehooks-ts.com/react-hook/use-window-size)

<!-- HOOKS:END -->
Expand Down
4 changes: 1 addition & 3 deletions packages/usehooks-ts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,12 @@
- [`useDebounceCallback()`](https://usehooks-ts.com/react-hook/use-debounce-callback)
- [`useDebounceValue()`](https://usehooks-ts.com/react-hook/use-debounce-value)
- [`useDocumentTitle()`](https://usehooks-ts.com/react-hook/use-document-title)
- [`useEffectOnce()`](https://usehooks-ts.com/react-hook/use-effect-once)
- [`useEventCallback()`](https://usehooks-ts.com/react-hook/use-event-callback)
- [`useEventListener()`](https://usehooks-ts.com/react-hook/use-event-listener)
- [`useHover()`](https://usehooks-ts.com/react-hook/use-hover)
- [`useIntersectionObserver()`](https://usehooks-ts.com/react-hook/use-intersection-observer)
- [`useInterval()`](https://usehooks-ts.com/react-hook/use-interval)
- [`useIsClient()`](https://usehooks-ts.com/react-hook/use-is-client)
- [`useIsFirstRender()`](https://usehooks-ts.com/react-hook/use-is-first-render)
- [`useIsMounted()`](https://usehooks-ts.com/react-hook/use-is-mounted)
- [`useIsomorphicLayoutEffect()`](https://usehooks-ts.com/react-hook/use-isomorphic-layout-effect)
- [`useLocalStorage()`](https://usehooks-ts.com/react-hook/use-local-storage)
Expand All @@ -68,7 +67,6 @@
- [`useTimeout()`](https://usehooks-ts.com/react-hook/use-timeout)
- [`useToggle()`](https://usehooks-ts.com/react-hook/use-toggle)
- [`useUnmount()`](https://usehooks-ts.com/react-hook/use-unmount)
- [`useUpdateEffect()`](https://usehooks-ts.com/react-hook/use-update-effect)
- [`useWindowSize()`](https://usehooks-ts.com/react-hook/use-window-size)

<!-- HOOKS:END -->
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { useEventCallback } from './useEventCallback'

export default function Component() {
const handleClick = useEventCallback(event => {
// Handle the event here
console.log('Clicked', event)
})

return <button onClick={handleClick}>Click me</button>
}
22 changes: 22 additions & 0 deletions packages/usehooks-ts/src/useEventCallback/useEventCallback.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
The `useEventCallback` hook is a utility for creating memoized event callback functions in React applications. It ensures that the provided callback function is memoized and stable across renders, while also preventing its invocation during the render phase.

See: [How to read an often-changing value from useCallback?](https://legacy.reactjs.org/docs/hooks-faq.html#how-to-read-an-often-changing-value-from-usecallback)

### Parameters

- `fn: (args) => result` - The callback function to be memoized.

### Return Value

- `(args) => result` - A memoized event callback function.

### Features

- **Memoization**: Optimizes performance by memoizing the callback function to avoid unnecessary re-renders.
- **Prevents Invocation During Render**: Ensures the callback isn't called during rendering, preventing potential issues.
- **Error Handling**: Throws an error if the callback is mistakenly invoked during rendering.
- **Strict Mode Compatibility**: Works seamlessly with React's strict mode for better debugging and reliability.

### Notes

Avoid using `useEventCallback` for callback functions that depend on frequently changing state or props.
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { fireEvent, render, renderHook, screen } from '@testing-library/react'

import { useEventCallback } from './useEventCallback'

describe('useEventCallback()', () => {
it('should not call the callback during render', () => {
const fn = vi.fn()
const { result } = renderHook(() => useEventCallback(fn))

render(<button onClick={result.current}>Click me</button>)

expect(fn).not.toHaveBeenCalled()
})

it('should call the callback when the event is triggered', () => {
const fn = vi.fn()
const { result } = renderHook(() => useEventCallback(fn))

render(<button onClick={result.current}>Click me</button>)

fireEvent.click(screen.getByText('Click me'))

expect(fn).toHaveBeenCalled()
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { useIsomorphicLayoutEffect } from '../useIsomorphicLayoutEffect'
* @template R - The return type of the event callback.
* @param {(...args: Args) => R} fn - The callback function.
* @returns {(...args: Args) => R} A memoized event callback function.
* @see [Documentation](https://usehooks-ts.com/react-hook/use-event-callback)
* @example
* const handleClick = useEventCallback((event) => {
* // Handle the event here
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { useLocalStorage } from './useLocalStorage'

// Usage
export default function Component() {
const [value, setValue] = useLocalStorage('test-key', 0)

Expand Down

0 comments on commit 7d74e09

Please sign in to comment.