Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // @flow
- /* eslint-env browser */
- import {useRef, useEffect} from 'react';
- function getDiff(a, b, properties) {
- const diff = {};
- if (properties.length === 0) {
- for (const property in b) {
- if (b.hasOwnProperty(property) && b[property] !== a[property]) {
- diff[property] = {
- prev: a[property],
- curr: b[property],
- };
- }
- }
- return diff;
- }
- return properties.reduce((result, property) => {
- if (b[property] !== a[property]) {
- result[property] = {
- prev: a[property],
- curr: b[property],
- };
- }
- return result;
- }, diff);
- }
- function getCopy(obj, properties) {
- const result = {};
- if (properties.length === 0) {
- for (const property in obj) {
- if (obj.hasOwnProperty(property)) {
- result[property] = obj[property];
- }
- }
- return result;
- }
- return properties.reduce((acc, property) => {
- if (process.env.NODE_ENV === 'development') {
- if (!obj.hasOwnProperty(property)) {
- console.trace(); // eslint-disable-line no-console
- console.error(
- `useComputedStyleObserver: computed style does not have own property: ${property}`
- );
- return acc;
- }
- }
- acc[property] = obj[property];
- return acc;
- }, result);
- }
- type DiffType = {[string]: {curr: string, prev: string}};
- /**
- * Observes the computed style for a single DOM node, and fires an onChange handler
- * if a diff exists.
- */
- export const useComputedStyleObserver = (
- /**
- * List of properties to diff against. The less there is the more performant. If
- * list is empty, all computed style properties will be checked
- */
- properties: Array<string>,
- /**
- * Callback that is invoked when a diff occurs
- */
- onStyleChange: (diff: DiffType) => void
- ) => {
- /**
- * Stores a single reference to the node's computed style that can
- * be observed for changes.
- */
- const computedStylesRef = useRef();
- /**
- * Stores a subset of the computed styles based on the list of properties
- */
- const stylesRef = useRef();
- const started = useRef(false);
- const animationFrameIDRef = useRef(null);
- useEffect(() => {
- function checkDiff() {
- const styles = stylesRef.current;
- const computedStyles = computedStylesRef.current;
- if (!styles || !computedStyles) {
- return;
- }
- started.current = true;
- const newStyles = getCopy(computedStyles, properties);
- const diff = getDiff(styles, newStyles, properties);
- if (Object.keys(diff).length) {
- stylesRef.current = newStyles;
- onStyleChange(diff);
- }
- animationFrameIDRef.current = requestAnimationFrame(checkDiff);
- }
- if (!started.current) {
- checkDiff();
- }
- });
- useEffect(() => {
- return () => {
- if (animationFrameIDRef.current) {
- cancelAnimationFrame(animationFrameIDRef.current);
- }
- };
- }, []);
- return {
- observe: (node: Element) => {
- const win = node.ownerDocument.defaultView;
- const computedStyles = win.getComputedStyle(node);
- computedStylesRef.current = computedStyles;
- stylesRef.current = getCopy(computedStyles, properties);
- },
- };
- };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement