use-presence.mjs 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. import { useContext, useId, useEffect, useCallback } from 'react';
  2. import { PresenceContext } from '../../context/PresenceContext.mjs';
  3. /**
  4. * When a component is the child of `AnimatePresence`, it can use `usePresence`
  5. * to access information about whether it's still present in the React tree.
  6. *
  7. * ```jsx
  8. * import { usePresence } from "framer-motion"
  9. *
  10. * export const Component = () => {
  11. * const [isPresent, safeToRemove] = usePresence()
  12. *
  13. * useEffect(() => {
  14. * !isPresent && setTimeout(safeToRemove, 1000)
  15. * }, [isPresent])
  16. *
  17. * return <div />
  18. * }
  19. * ```
  20. *
  21. * If `isPresent` is `false`, it means that a component has been removed the tree, but
  22. * `AnimatePresence` won't really remove it until `safeToRemove` has been called.
  23. *
  24. * @public
  25. */
  26. function usePresence(subscribe = true) {
  27. const context = useContext(PresenceContext);
  28. if (context === null)
  29. return [true, null];
  30. const { isPresent, onExitComplete, register } = context;
  31. // It's safe to call the following hooks conditionally (after an early return) because the context will always
  32. // either be null or non-null for the lifespan of the component.
  33. const id = useId();
  34. useEffect(() => {
  35. if (subscribe) {
  36. return register(id);
  37. }
  38. }, [subscribe]);
  39. const safeToRemove = useCallback(() => subscribe && onExitComplete && onExitComplete(id), [id, onExitComplete, subscribe]);
  40. return !isPresent && onExitComplete ? [false, safeToRemove] : [true];
  41. }
  42. /**
  43. * Similar to `usePresence`, except `useIsPresent` simply returns whether or not the component is present.
  44. * There is no `safeToRemove` function.
  45. *
  46. * ```jsx
  47. * import { useIsPresent } from "framer-motion"
  48. *
  49. * export const Component = () => {
  50. * const isPresent = useIsPresent()
  51. *
  52. * useEffect(() => {
  53. * !isPresent && console.log("I've been removed!")
  54. * }, [isPresent])
  55. *
  56. * return <div />
  57. * }
  58. * ```
  59. *
  60. * @public
  61. */
  62. function useIsPresent() {
  63. return isPresent(useContext(PresenceContext));
  64. }
  65. function isPresent(context) {
  66. return context === null ? true : context.isPresent;
  67. }
  68. export { isPresent, useIsPresent, usePresence };