@elastic/eui
Version:
Elastic UI Component Library
62 lines (57 loc) • 2.84 kB
JavaScript
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import { useCallback, useEffect, useRef } from 'react';
/**
* A shared custom hook that provides a pattern for observing DOM nodes
* via browser observer APIs. Used by `EuiResizeObserver` and `EuiMutationObserver`.
*
* @param beginObserve - A callback that receives the target DOM element and should
* create and return the observer instance (e.g., `ResizeObserver`).
* @param componentName - Optional name used in error messages when no ref is
* attached on mount, mirroring the guard previously in `EuiObserver`.
*/
export var useObserver = function useObserver(beginObserve) {
var componentName = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'useObserver';
var childNodeRef = useRef(null);
var observerRef = useRef(null);
// Store beginObserve in a ref so the ref callback doesn't cycle
var beginObserveRef = useRef(beginObserve);
beginObserveRef.current = beginObserve;
// Store componentName in a ref so the mount-only effect can access the
// latest value without needing it as a dependency.
var componentNameRef = useRef(componentName);
componentNameRef.current = componentName;
// Guard: throw if the ref callback was never called (no element attached),
// mirroring the check previously in EuiObserver.componentDidMount.
// Also cleans up the observer on unmount.
// Empty deps: run only on mount/unmount — componentName is only used for the
// error message and changing it must not disconnect/re-connect the observer.
useEffect(function () {
if (childNodeRef.current == null) {
throw new Error("".concat(componentNameRef.current, " did not receive a ref"));
}
return function () {
var _observerRef$current;
(_observerRef$current = observerRef.current) === null || _observerRef$current === void 0 || _observerRef$current.disconnect();
};
}, []);
var updateChildNode = useCallback(function (ref) {
if (childNodeRef.current === ref) return; // node hasn't changed
// if there's an existing observer disconnect it
if (observerRef.current != null) {
observerRef.current.disconnect();
observerRef.current = null;
}
childNodeRef.current = ref;
if (childNodeRef.current != null) {
var _beginObserveRef$curr;
observerRef.current = (_beginObserveRef$curr = beginObserveRef.current(childNodeRef.current)) !== null && _beginObserveRef$curr !== void 0 ? _beginObserveRef$curr : null;
}
}, []);
return updateChildNode;
};