Skip to content

Warning: ref.measureLayout must be called with a ref to a native component#614

Description

@dangervalentine

Hi! 馃憢

Thanks for your work on this project!

Summary

When using NestableScrollContainer + NestableDraggableFlatList (one per section), React Native logs this warning once per nested list:

Warning: ref.measureLayout must be called with a ref to a native component.

This appears to be caused by calling measureLayout with a findNodeHandle(...) result (a node handle number) instead of a native component ref. Passing the scrollableRef.current directly fixes the warning.

I patched react-native-draggable-flatlist@4.0.3 via patch-package as a workaround.

Patch (diff)

diff --git a/node_modules/react-native-draggable-flatlist/src/components/NestableDraggableFlatList.tsx b/node_modules/react-native-draggable-flatlist/src/components/NestableDraggableFlatList.tsx
index 1559352..2ab50ad 100644
--- a/node_modules/react-native-draggable-flatlist/src/components/NestableDraggableFlatList.tsx
+++ b/node_modules/react-native-draggable-flatlist/src/components/NestableDraggableFlatList.tsx
@@ -1,8 +1,8 @@
 import React, { useRef, useState } from "react";
-import { findNodeHandle, LogBox } from "react-native";
+import { LogBox } from "react-native";
 import Animated, {
-  useDerivedValue,
-  useSharedValue,
+    useDerivedValue,
+    useSharedValue,
 } from "react-native-reanimated";
 import { DraggableFlatListProps } from "../types";
 import DraggableFlatList from "../components/DraggableFlatList";
@@ -13,97 +13,99 @@ import { useStableCallback } from "../hooks/useStableCallback";
 import { FlatList } from "react-native-gesture-handler";
 
 function NestableDraggableFlatListInner<T>(
-  props: DraggableFlatListProps<T>,
-  ref?: React.ForwardedRef<FlatList<T>>
+    props: DraggableFlatListProps<T>,
+    ref?: React.ForwardedRef<FlatList<T>>
 ) {
-  const hasSuppressedWarnings = useRef(false);
+    const hasSuppressedWarnings = useRef(false);
 
-  if (!hasSuppressedWarnings.current) {
-    LogBox.ignoreLogs([
-      "VirtualizedLists should never be nested inside plain ScrollViews with the same orientation because it can break windowing",
-    ]); // Ignore log notification by message
-    //@ts-ignore
-    console.reportErrorsAsExceptions = false;
-    hasSuppressedWarnings.current = true;
-  }
+    if (!hasSuppressedWarnings.current) {
+        LogBox.ignoreLogs([
+            "VirtualizedLists should never be nested inside plain ScrollViews with the same orientation because it can break windowing",
+        ]); // Ignore log notification by message
+        //@ts-ignore
+        console.reportErrorsAsExceptions = false;
+        hasSuppressedWarnings.current = true;
+    }
 
-  const {
-    scrollableRef,
-    outerScrollOffset,
-    setOuterScrollEnabled,
-  } = useSafeNestableScrollContainerContext();
+    const {
+        scrollableRef,
+        outerScrollOffset,
+        setOuterScrollEnabled,
+    } = useSafeNestableScrollContainerContext();
 
-  const listVerticalOffset = useSharedValue(0);
-  const [animVals, setAnimVals] = useState({});
-  const defaultHoverOffset = useSharedValue(0);
-  const [listHoverOffset, setListHoverOffset] = useState(defaultHoverOffset);
+    const listVerticalOffset = useSharedValue(0);
+    const [animVals, setAnimVals] = useState({});
+    const defaultHoverOffset = useSharedValue(0);
+    const [listHoverOffset, setListHoverOffset] = useState(defaultHoverOffset);
 
-  const hoverOffset = useDerivedValue(() => {
-    return listHoverOffset.value + listVerticalOffset.value;
-  }, [listHoverOffset]);
+    const hoverOffset = useDerivedValue(() => {
+        return listHoverOffset.value + listVerticalOffset.value;
+    }, [listHoverOffset]);
 
-  useNestedAutoScroll({
-    ...animVals,
-    hoverOffset,
-  });
+    useNestedAutoScroll({
+        ...animVals,
+        hoverOffset,
+    });
 
-  const onListContainerLayout = useStableCallback(async ({ containerRef }) => {
-    const nodeHandle = findNodeHandle(scrollableRef.current);
+    const onListContainerLayout = useStableCallback(async ({ containerRef }) => {
+        const scrollNode = scrollableRef.current;
+        const containerNode = containerRef.current;
 
-    const onSuccess = (_x: number, y: number) => {
-      listVerticalOffset.value = y;
-    };
-    const onFail = () => {
-      console.log("## nested draggable list measure fail");
-    };
-    //@ts-ignore
-    containerRef.current.measureLayout(nodeHandle, onSuccess, onFail);
-  });
+        if (!scrollNode || !containerNode) return;
 
-  const onDragBegin: DraggableFlatListProps<T>["onDragBegin"] = useStableCallback(
-    (params) => {
-      setOuterScrollEnabled(false);
-      props.onDragBegin?.(params);
-    }
-  );
+        const onSuccess = (_x: number, y: number) => {
+            listVerticalOffset.value = y;
+        };
+        const onFail = () => {
+            console.log("## nested draggable list measure fail");
+        };
+        containerNode.measureLayout(scrollNode, onSuccess, onFail);
+    });
 
-  const onDragEnd: DraggableFlatListProps<T>["onDragEnd"] = useStableCallback(
-    (params) => {
-      setOuterScrollEnabled(true);
-      props.onDragEnd?.(params);
-    }
-  );
+    const onDragBegin: DraggableFlatListProps<T>["onDragBegin"] = useStableCallback(
+        (params) => {
+            setOuterScrollEnabled(false);
+            props.onDragBegin?.(params);
+        }
+    );
 
-  const onAnimValInit: DraggableFlatListProps<T>["onAnimValInit"] = useStableCallback(
-    (params) => {
-      setListHoverOffset(params.hoverOffset);
-      setAnimVals({
-        ...params,
-        hoverOffset,
-      });
-      props.onAnimValInit?.(params);
-    }
-  );
+    const onDragEnd: DraggableFlatListProps<T>["onDragEnd"] = useStableCallback(
+        (params) => {
+            setOuterScrollEnabled(true);
+            props.onDragEnd?.(params);
+        }
+    );
+
+    const onAnimValInit: DraggableFlatListProps<T>["onAnimValInit"] = useStableCallback(
+        (params) => {
+            setListHoverOffset(params.hoverOffset);
+            setAnimVals({
+                ...params,
+                hoverOffset,
+            });
+            props.onAnimValInit?.(params);
+        }
+    );
 
-  return (
-    <DraggableFlatList
-      ref={ref}
-      onContainerLayout={onListContainerLayout}
-      activationDistance={props.activationDistance || 20}
-      scrollEnabled={false}
-      {...props}
-      outerScrollOffset={outerScrollOffset}
-      onDragBegin={onDragBegin}
-      onDragEnd={onDragEnd}
-      onAnimValInit={onAnimValInit}
-    />
-  );
+    return (
+        <DraggableFlatList
+            ref={ref}
+            onContainerLayout={onListContainerLayout}
+            activationDistance={props.activationDistance || 20}
+            scrollEnabled={false}
+            {...props}
+            outerScrollOffset={outerScrollOffset}
+            onDragBegin={onDragBegin}
+            onDragEnd={onDragEnd}
+            onAnimValInit={onAnimValInit}
+        />
+    );
 }
 
 // Generic forwarded ref type assertion taken from:
 // https://fettblog.eu/typescript-react-generic-forward-refs/#option-1%3A-type-assertion
 export const NestableDraggableFlatList = React.forwardRef(
-  NestableDraggableFlatListInner
+    NestableDraggableFlatListInner
 ) as <T>(
-  props: DraggableFlatListProps<T> & { ref?: React.ForwardedRef<FlatList<T>> }
+    props: DraggableFlatListProps<T> & { ref?: React.ForwardedRef<FlatList<T>> }
 ) => ReturnType<typeof NestableDraggableFlatListInner>;

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions