streamich / react-use

React Hooks — 👍
http://streamich.github.io/react-use
The Unlicense
42.03k stars 3.17k forks source link

[request]Mutation Observer API #1202

Open devvit opened 4 years ago

devvit commented 4 years ago

Is your feature request related to a problem? Please describe. There should be three modern observers: Intersection Observer API => useIntersection ☑️ Resize Observer API => useMeasure ☑️ Mutation Observer API => useMutation ✖️

Describe the solution you'd like


useMutation(wrapper, options, () => {})
// OR
[wrapper] = useMutation(options, () => {})

<A ref={wrapper}></A>
vincerubinetti commented 2 years ago

Possible reference: https://vueuse.org/core/usemutationobserver/#usemutationobserver

kayac-chang commented 1 year ago

For reference, this is my current implementation.

This implementation follow useIntersection API design.

useMutationObserver

import type { RefObject } from "react";
import { useEffect, useState } from "react";

export function useMutationObserver<T extends Node>(
  ref: RefObject<T>,
  options: MutationObserverInit
) {
  const [mutations, setMutations] = useState<MutationRecord[]>();

  useEffect(() => {
    if (!ref.current || typeof MutationObserver !== "function") {
      return () => {};
    }

    const handler = (mutations: MutationRecord[]) => setMutations(mutations);
    const observer = new MutationObserver(handler);
    observer.observe(ref.current, options);

    return () => {
      setMutations(undefined);
      observer.disconnect();
    };
  }, [ref, options]);

  return mutations;
}

Example Usage

  const messageEl = useRef<HTMLUListElement>(null);
  const mutations = useMutationObserver(messageEl, {
    childList: true,
    subtree: true,
  });
  useEffect(() => {
    const target = messageEl.current;

    // if any update in the message list, scroll to the latest message
    if (mutations && target) {
      window.scroll({ top: target.scrollHeight, behavior: "smooth" });
    }
  }, [mutations]);