use-ref-with-auto-focus.ts 1016 B

123456789101112131415161718192021222324252627282930313233343536
  1. import { useRef, useEffect, useCallback, useState } from 'react'
  2. export function useRefWithAutoFocus<T extends HTMLElement = HTMLElement>() {
  3. const autoFocusedRef = useRef<T>(null)
  4. const [hasFocused, setHasFocused] = useState(false)
  5. const resetAutoFocus = useCallback(() => setHasFocused(false), [])
  6. // Run on every render but use hasFocused to ensure that the autofocus only
  7. // happens once
  8. useEffect(() => {
  9. if (hasFocused) {
  10. return
  11. }
  12. let request: number | null = null
  13. if (autoFocusedRef.current) {
  14. request = window.requestAnimationFrame(() => {
  15. if (autoFocusedRef.current) {
  16. autoFocusedRef.current.focus()
  17. setHasFocused(true)
  18. request = null
  19. }
  20. })
  21. }
  22. // Cancel a pending autofocus prior to autofocus actually happening on
  23. // render, and on unmount
  24. return () => {
  25. if (request !== null) {
  26. window.cancelAnimationFrame(request)
  27. }
  28. }
  29. })
  30. return { autoFocusedRef, resetAutoFocus }
  31. }