Skip to content

Conversation

tjzel
Copy link
Collaborator

@tjzel tjzel commented Sep 25, 2025

Summary

Fixes #8294

I went down the rabbit hole to find how to obtain proper node handles and host instances for Shadow Node Wrapper.

I tested the following components:

  • React Native:
    • ActivityIndicator
    • Button
    • FlatList
    • Image
    • ImageBackground
    • KeyboardAvoidingView
    • Modal
    • Pressable
    • RefreshControl
    • ScrollView
    • SectionList
    • Switch
    • Text
    • TextInput
    • TouchableHighlight
    • TouchableOpacity
    • TouchableWithoutFeedback
    • View
    • VirtualizedList
  • Shopify:
    • FlashList
  • React Native Gesture Handler:
    • ScrollView
  • React Native SVG
    • Path

Native results

Logs from native Fabric

[
  {
    "name": "ActivityIndicator",
    "objectId": 1,
    "findNodeHandle()": "TAG 1",
    "__internalInstanceHandle": {
      "objectId": 2,
      "findNodeHandle()": "ERROR",
      "findHostInstance_DEPRECATED()": "ERROR",
      "stateNode.node": {
        "objectId": 3,
        "findNodeHandle()": "ERROR",
        "findHostInstance_DEPRECATED()": "ERROR",
        "shadowNodeWrapper": "SHADOW_NODE_WRAPPER 1",
        "shadowNodeWrapperTag": "TAG 1"
      }
    },
    "findHostInstance_DEPRECATED()": "ERROR",
    "deepShadowNodeWrappersProps": {
      ".__internalInstanceHandle.stateNode.node": {
        "shadowNodeWrapper": "SHADOW_NODE_WRAPPER 1",
        "shadowNodeWrapperTag": "TAG 1"
      }
    }
  },

  {
    "name": "Button",
    "objectId": 1,
    "findNodeHandle()": "TAG 1",
    "__internalInstanceHandle": {
      "objectId": 2,
      "findNodeHandle()": "ERROR",
      "findHostInstance_DEPRECATED()": "ERROR",
      "stateNode.node": {
        "objectId": 3,
        "findNodeHandle()": "ERROR",
        "findHostInstance_DEPRECATED()": "ERROR",
        "shadowNodeWrapper": "SHADOW_NODE_WRAPPER 1",
        "shadowNodeWrapperTag": "TAG 1"
      }
    },
    "findHostInstance_DEPRECATED()": "ERROR",
    "deepShadowNodeWrappersProps": {
      ".__internalInstanceHandle.stateNode.node": {
        "shadowNodeWrapper": "SHADOW_NODE_WRAPPER 1",
        "shadowNodeWrapperTag": "TAG 1"
      }
    }
  },

  {
    "name": "FlatList",
    "objectId": 1,
    "findNodeHandle()": "TAG 1",
    "getScrollableNode()": "TAG 1",
    "getScrollResponder()": {
      "objectId": 3,
      "findNodeHandle()": "TAG 1",
      "getScrollableNode()": "TAG 1",
      "getScrollResponder()": "OBJECT 3",
      "getNativeScrollRef()": "OBJECT 2",
      "findHostInstance_DEPRECATED()": "OBJECT 2",
      "_reactInternals": "PRESENT"
    },
    "getNativeScrollRef()": {
      "objectId": 2,
      "findNodeHandle()": "TAG 1",
      "getScrollableNode()": "TAG 1",
      "getScrollResponder()": "OBJECT 3",
      "getNativeScrollRef()": "OBJECT 2",
      "__internalInstanceHandle": {
        "objectId": 4,
        "findNodeHandle()": "ERROR",
        "findHostInstance_DEPRECATED()": "ERROR",
        "stateNode.node": {
          "objectId": 5,
          "findNodeHandle()": "ERROR",
          "findHostInstance_DEPRECATED()": "ERROR",
          "shadowNodeWrapper": "SHADOW_NODE_WRAPPER 1",
          "shadowNodeWrapperTag": "TAG 1"
        }
      },
      "findHostInstance_DEPRECATED()": "ERROR"
    },
    "findHostInstance_DEPRECATED()": "OBJECT 2",
    "_reactInternals": "PRESENT",
    "deepShadowNodeWrappersProps": {
      "._listRef._scrollRef.__internalInstanceHandle.stateNode.node": {
        "shadowNodeWrapper": "SHADOW_NODE_WRAPPER 1",
        "shadowNodeWrapperTag": "TAG 1"
      },
      ".getScrollResponder()._innerView.nativeInstance.__internalInstanceHandle.stateNode.node": {
        "shadowNodeWrapper": "SHADOW_NODE_WRAPPER 2",
        "shadowNodeWrapperTag": "TAG 2"
      }
    }
  },

  {
    "name": "Image",
    "objectId": 1,
    "findNodeHandle()": "TAG 1",
    "__internalInstanceHandle": {
      "objectId": 2,
      "findNodeHandle()": "ERROR",
      "findHostInstance_DEPRECATED()": "ERROR",
      "stateNode.node": {
        "objectId": 3,
        "findNodeHandle()": "ERROR",
        "findHostInstance_DEPRECATED()": "ERROR",
        "shadowNodeWrapper": "SHADOW_NODE_WRAPPER 1",
        "shadowNodeWrapperTag": "TAG 1"
      }
    },
    "findHostInstance_DEPRECATED()": "ERROR",
    "deepShadowNodeWrappersProps": {
      ".__internalInstanceHandle.stateNode.node": {
        "shadowNodeWrapper": "SHADOW_NODE_WRAPPER 1",
        "shadowNodeWrapperTag": "TAG 1"
      }
    }
  },

  {
    "name": "ImageBackground",
    "objectId": 1,
    "findNodeHandle()": "TAG 1",
    "findHostInstance_DEPRECATED()": {
      "objectId": 2,
      "findNodeHandle()": "TAG 1",
      "__internalInstanceHandle": {
        "objectId": 3,
        "findNodeHandle()": "ERROR",
        "findHostInstance_DEPRECATED()": "ERROR",
        "stateNode.node": {
          "objectId": 4,
          "findNodeHandle()": "ERROR",
          "findHostInstance_DEPRECATED()": "ERROR",
          "shadowNodeWrapper": "SHADOW_NODE_WRAPPER 1",
          "shadowNodeWrapperTag": "TAG 1"
        }
      },
      "findHostInstance_DEPRECATED()": "ERROR"
    },
    "_reactInternals": "PRESENT",
    "deepShadowNodeWrappersProps": {
      "._viewRef.__internalInstanceHandle.stateNode.node": {
        "shadowNodeWrapper": "SHADOW_NODE_WRAPPER 1",
        "shadowNodeWrapperTag": "TAG 1"
      }
    }
  },

  {
    "name": "KeyboardAvoidingView",
    "objectId": 1,
    "findNodeHandle()": "TAG 1",
    "findHostInstance_DEPRECATED()": {
      "objectId": 2,
      "findNodeHandle()": "TAG 1",
      "__internalInstanceHandle": {
        "objectId": 3,
        "findNodeHandle()": "ERROR",
        "findHostInstance_DEPRECATED()": "ERROR",
        "stateNode.node": {
          "objectId": 4,
          "findNodeHandle()": "ERROR",
          "findHostInstance_DEPRECATED()": "ERROR",
          "shadowNodeWrapper": "SHADOW_NODE_WRAPPER 1",
          "shadowNodeWrapperTag": "TAG 1"
        }
      },
      "findHostInstance_DEPRECATED()": "ERROR"
    },
    "_reactInternals": "PRESENT",
    "deepShadowNodeWrappersProps": {
      ".viewRef.current.__internalInstanceHandle.stateNode.node": {
        "shadowNodeWrapper": "SHADOW_NODE_WRAPPER 1",
        "shadowNodeWrapperTag": "TAG 1"
      }
    }
  },

  {
    "name": "Pressable",
    "objectId": 1,
    "findNodeHandle()": "TAG 1",
    "__internalInstanceHandle": {
      "objectId": 2,
      "findNodeHandle()": "ERROR",
      "findHostInstance_DEPRECATED()": "ERROR",
      "stateNode.node": {
        "objectId": 3,
        "findNodeHandle()": "ERROR",
        "findHostInstance_DEPRECATED()": "ERROR",
        "shadowNodeWrapper": "SHADOW_NODE_WRAPPER 1",
        "shadowNodeWrapperTag": "TAG 1"
      }
    },
    "findHostInstance_DEPRECATED()": "ERROR",
    "deepShadowNodeWrappersProps": {
      ".__internalInstanceHandle.stateNode.node": {
        "shadowNodeWrapper": "SHADOW_NODE_WRAPPER 1",
        "shadowNodeWrapperTag": "TAG 1"
      }
    }
  },

  {
    "name": "RefreshControl",
    "objectId": 1,
    "findNodeHandle()": "TAG 1",
    "findHostInstance_DEPRECATED()": {
      "objectId": 2,
      "findNodeHandle()": "TAG 1",
      "__internalInstanceHandle": {
        "objectId": 3,
        "findNodeHandle()": "ERROR",
        "findHostInstance_DEPRECATED()": "ERROR",
        "stateNode.node": {
          "objectId": 4,
          "findNodeHandle()": "ERROR",
          "findHostInstance_DEPRECATED()": "ERROR",
          "shadowNodeWrapper": "SHADOW_NODE_WRAPPER 1",
          "shadowNodeWrapperTag": "TAG 1"
        }
      },
      "findHostInstance_DEPRECATED()": "ERROR"
    },
    "_reactInternals": "PRESENT",
    "deepShadowNodeWrappersProps": {
      "._nativeRef.__internalInstanceHandle.stateNode.node": {
        "shadowNodeWrapper": "SHADOW_NODE_WRAPPER 1",
        "shadowNodeWrapperTag": "TAG 1"
      }
    }
  },

  {
    "name": "ScrollView",
    "objectId": 1,
    "findNodeHandle()": "TAG 1",
    "getScrollableNode()": "TAG 1",
    "getScrollResponder()": {
      "objectId": 2,
      "findNodeHandle()": "TAG 1",
      "getScrollableNode()": "TAG 1",
      "getScrollResponder()": "OBJECT 2",
      "getNativeScrollRef()": "OBJECT 1",
      "findHostInstance_DEPRECATED()": "OBJECT 1",
      "_reactInternals": "PRESENT"
    },
    "getNativeScrollRef()": "OBJECT 1",
    "__internalInstanceHandle": {
      "objectId": 3,
      "findNodeHandle()": "ERROR",
      "findHostInstance_DEPRECATED()": "ERROR",
      "stateNode.node": {
        "objectId": 4,
        "findNodeHandle()": "ERROR",
        "findHostInstance_DEPRECATED()": "ERROR",
        "shadowNodeWrapper": "SHADOW_NODE_WRAPPER 1",
        "shadowNodeWrapperTag": "TAG 1"
      }
    },
    "findHostInstance_DEPRECATED()": "ERROR",
    "deepShadowNodeWrappersProps": {
      ".__internalInstanceHandle.stateNode.node": {
        "shadowNodeWrapper": "SHADOW_NODE_WRAPPER 1",
        "shadowNodeWrapperTag": "TAG 1"
      },
      ".getScrollResponder()._innerView.nativeInstance.__internalInstanceHandle.stateNode.node": {
        "shadowNodeWrapper": "SHADOW_NODE_WRAPPER 2",
        "shadowNodeWrapperTag": "TAG 2"
      }
    }
  },

  {
    "name": "SectionList",
    "objectId": 1,
    "findNodeHandle()": "TAG 1",
    "getScrollableNode()": "TAG 1",
    "getScrollResponder()": {
      "objectId": 2,
      "findNodeHandle()": "TAG 1",
      "getScrollableNode()": "TAG 1",
      "getScrollResponder()": "OBJECT 2",
      "getNativeScrollRef()": "OBJECT 3",
      "findHostInstance_DEPRECATED()": "OBJECT 3",
      "_reactInternals": "PRESENT"
    },
    "findHostInstance_DEPRECATED()": {
      "objectId": 3,
      "findNodeHandle()": "TAG 1",
      "getScrollableNode()": "TAG 1",
      "getScrollResponder()": "OBJECT 2",
      "getNativeScrollRef()": "OBJECT 3",
      "__internalInstanceHandle": {
        "objectId": 4,
        "findNodeHandle()": "ERROR",
        "findHostInstance_DEPRECATED()": "ERROR",
        "stateNode.node": {
          "objectId": 5,
          "findNodeHandle()": "ERROR",
          "findHostInstance_DEPRECATED()": "ERROR",
          "shadowNodeWrapper": "SHADOW_NODE_WRAPPER 1",
          "shadowNodeWrapperTag": "TAG 1"
        }
      },
      "findHostInstance_DEPRECATED()": "ERROR"
    },
    "_reactInternals": "PRESENT",
    "deepShadowNodeWrappersProps": {
      "._wrapperListRef._listRef._scrollRef.__internalInstanceHandle.stateNode.node": {
        "shadowNodeWrapper": "SHADOW_NODE_WRAPPER 1",
        "shadowNodeWrapperTag": "TAG 1"
      },
      ".getScrollResponder()._innerView.nativeInstance.__internalInstanceHandle.stateNode.node": {
        "shadowNodeWrapper": "SHADOW_NODE_WRAPPER 2",
        "shadowNodeWrapperTag": "TAG 2"
      }
    }
  },

  {
    "name": "Switch",
    "objectId": 1,
    "findNodeHandle()": "TAG 1",
    "__internalInstanceHandle": {
      "objectId": 2,
      "findNodeHandle()": "ERROR",
      "findHostInstance_DEPRECATED()": "ERROR",
      "stateNode.node": {
        "objectId": 3,
        "findNodeHandle()": "ERROR",
        "findHostInstance_DEPRECATED()": "ERROR",
        "shadowNodeWrapper": "SHADOW_NODE_WRAPPER 1",
        "shadowNodeWrapperTag": "TAG 1"
      }
    },
    "findHostInstance_DEPRECATED()": "ERROR",
    "deepShadowNodeWrappersProps": {
      ".__internalInstanceHandle.stateNode.node": {
        "shadowNodeWrapper": "SHADOW_NODE_WRAPPER 1",
        "shadowNodeWrapperTag": "TAG 1"
      }
    }
  },

  {
    "name": "Text",
    "objectId": 1,
    "findNodeHandle()": "TAG 1",
    "__internalInstanceHandle": {
      "objectId": 2,
      "findNodeHandle()": "ERROR",
      "findHostInstance_DEPRECATED()": "ERROR",
      "stateNode.node": {
        "objectId": 3,
        "findNodeHandle()": "ERROR",
        "findHostInstance_DEPRECATED()": "ERROR",
        "shadowNodeWrapper": "SHADOW_NODE_WRAPPER 1",
        "shadowNodeWrapperTag": "TAG 1"
      }
    },
    "findHostInstance_DEPRECATED()": "ERROR",
    "deepShadowNodeWrappersProps": {
      ".__internalInstanceHandle.stateNode.node": {
        "shadowNodeWrapper": "SHADOW_NODE_WRAPPER 1",
        "shadowNodeWrapperTag": "TAG 1"
      }
    }
  },

  {
    "name": "TextInput",
    "objectId": 1,
    "findNodeHandle()": "TAG 1",
    "__internalInstanceHandle": {
      "objectId": 2,
      "findNodeHandle()": "ERROR",
      "findHostInstance_DEPRECATED()": "ERROR",
      "stateNode.node": {
        "objectId": 3,
        "findNodeHandle()": "ERROR",
        "findHostInstance_DEPRECATED()": "ERROR",
        "shadowNodeWrapper": "SHADOW_NODE_WRAPPER 1",
        "shadowNodeWrapperTag": "TAG 1"
      }
    },
    "findHostInstance_DEPRECATED()": "ERROR",
    "deepShadowNodeWrappersProps": {
      ".__internalInstanceHandle.stateNode.node": {
        "shadowNodeWrapper": "SHADOW_NODE_WRAPPER 1",
        "shadowNodeWrapperTag": "TAG 1"
      }
    }
  },

  {
    "name": "TouchableHighlight",
    "objectId": 1,
    "findNodeHandle()": "TAG 1",
    "__internalInstanceHandle": {
      "objectId": 2,
      "findNodeHandle()": "ERROR",
      "findHostInstance_DEPRECATED()": "ERROR",
      "stateNode.node": {
        "objectId": 3,
        "findNodeHandle()": "ERROR",
        "findHostInstance_DEPRECATED()": "ERROR",
        "shadowNodeWrapper": "SHADOW_NODE_WRAPPER 1",
        "shadowNodeWrapperTag": "TAG 1"
      }
    },
    "findHostInstance_DEPRECATED()": "ERROR",
    "deepShadowNodeWrappersProps": {
      ".__internalInstanceHandle.stateNode.node": {
        "shadowNodeWrapper": "SHADOW_NODE_WRAPPER 1",
        "shadowNodeWrapperTag": "TAG 1"
      }
    }
  },

  {
    "name": "TouchableOpacity",
    "objectId": 1,
    "findNodeHandle()": "TAG 1",
    "__internalInstanceHandle": {
      "objectId": 2,
      "findNodeHandle()": "ERROR",
      "findHostInstance_DEPRECATED()": "ERROR",
      "stateNode.node": {
        "objectId": 3,
        "findNodeHandle()": "ERROR",
        "findHostInstance_DEPRECATED()": "ERROR",
        "shadowNodeWrapper": "SHADOW_NODE_WRAPPER 1",
        "shadowNodeWrapperTag": "TAG 1"
      }
    },
    "findHostInstance_DEPRECATED()": "ERROR",
    "deepShadowNodeWrappersProps": {
      ".__internalInstanceHandle.stateNode.node": {
        "shadowNodeWrapper": "SHADOW_NODE_WRAPPER 1",
        "shadowNodeWrapperTag": "TAG 1"
      }
    }
  },

  {
    "name": "VirtualizedList",
    "objectId": 1,
    "findNodeHandle()": "TAG 1",
    "getScrollableNode()": "TAG 1",
    "getScrollResponder()": {
      "objectId": 3,
      "findNodeHandle()": "TAG 1",
      "getScrollableNode()": "TAG 1",
      "getScrollResponder()": "OBJECT 3",
      "getNativeScrollRef()": "OBJECT 2",
      "findHostInstance_DEPRECATED()": "OBJECT 2",
      "_reactInternals": "PRESENT"
    },
    "getScrollRef()": {
      "objectId": 2,
      "findNodeHandle()": "TAG 1",
      "getScrollableNode()": "TAG 1",
      "getScrollResponder()": "OBJECT 3",
      "getNativeScrollRef()": "OBJECT 2",
      "__internalInstanceHandle": {
        "objectId": 4,
        "findNodeHandle()": "ERROR",
        "findHostInstance_DEPRECATED()": "ERROR",
        "stateNode.node": {
          "objectId": 5,
          "findNodeHandle()": "ERROR",
          "findHostInstance_DEPRECATED()": "ERROR",
          "shadowNodeWrapper": "SHADOW_NODE_WRAPPER 1",
          "shadowNodeWrapperTag": "TAG 1"
        }
      },
      "findHostInstance_DEPRECATED()": "ERROR"
    },
    "findHostInstance_DEPRECATED()": "OBJECT 2",
    "_reactInternals": "PRESENT",
    "deepShadowNodeWrappersProps": {
      "._scrollRef.__internalInstanceHandle.stateNode.node": {
        "shadowNodeWrapper": "SHADOW_NODE_WRAPPER 1",
        "shadowNodeWrapperTag": "TAG 1"
      },
      ".getScrollResponder()._innerView.nativeInstance.__internalInstanceHandle.stateNode.node": {
        "shadowNodeWrapper": "SHADOW_NODE_WRAPPER 2",
        "shadowNodeWrapperTag": "TAG 2"
      }
    }
  },

  {
    "name": "View",
    "objectId": 1,
    "findNodeHandle()": "TAG 1",
    "__internalInstanceHandle": {
      "objectId": 2,
      "findNodeHandle()": "ERROR",
      "findHostInstance_DEPRECATED()": "ERROR",
      "stateNode.node": {
        "objectId": 3,
        "findNodeHandle()": "ERROR",
        "findHostInstance_DEPRECATED()": "ERROR",
        "shadowNodeWrapper": "SHADOW_NODE_WRAPPER 1",
        "shadowNodeWrapperTag": "TAG 1"
      }
    },
    "findHostInstance_DEPRECATED()": "ERROR",
    "deepShadowNodeWrappersProps": {
      ".__internalInstanceHandle.stateNode.node": {
        "shadowNodeWrapper": "SHADOW_NODE_WRAPPER 1",
        "shadowNodeWrapperTag": "TAG 1"
      }
    }
  },

  {
    "name": "FlashList",
    "objectId": 1,
    "findNodeHandle()": "TAG 1",
    "getScrollableNode()": "TAG 1",
    "getScrollResponder()": {
      "objectId": 3,
      "findNodeHandle()": "TAG 1",
      "getScrollableNode()": "TAG 1",
      "getScrollResponder()": "OBJECT 3",
      "getNativeScrollRef()": "OBJECT 2",
      "findHostInstance_DEPRECATED()": "OBJECT 2",
      "_reactInternals": "PRESENT"
    },
    "getNativeScrollRef()": {
      "objectId": 2,
      "findNodeHandle()": "TAG 1",
      "getScrollableNode()": "TAG 1",
      "getScrollResponder()": "OBJECT 3",
      "getNativeScrollRef()": "OBJECT 2",
      "__internalInstanceHandle": "OBJECT 4",
      "findHostInstance_DEPRECATED()": "ERROR"
    },
    "__internalInstanceHandle": {
      "objectId": 4,
      "findNodeHandle()": "ERROR",
      "findHostInstance_DEPRECATED()": "ERROR",
      "stateNode.node": {
        "objectId": 5,
        "findNodeHandle()": "ERROR",
        "findHostInstance_DEPRECATED()": "ERROR",
        "shadowNodeWrapper": "SHADOW_NODE_WRAPPER 1",
        "shadowNodeWrapperTag": "TAG 1"
      }
    },
    "findHostInstance_DEPRECATED()": "ERROR",
    "deepShadowNodeWrappersProps": {
      ".__internalInstanceHandle.stateNode.node": {
        "shadowNodeWrapper": "SHADOW_NODE_WRAPPER 1",
        "shadowNodeWrapperTag": "TAG 1"
      },
      ".getScrollResponder()._innerView.nativeInstance.__internalInstanceHandle.stateNode.node": {
        "shadowNodeWrapper": "SHADOW_NODE_WRAPPER 2",
        "shadowNodeWrapperTag": "TAG 2"
      }
    }
  },

  {
    "name": "RNGHScrollView",
    "objectId": 1,
    "findNodeHandle()": "TAG 1",
    "getScrollableNode()": "TAG 1",
    "getScrollResponder()": {
      "objectId": 2,
      "findNodeHandle()": "TAG 1",
      "getScrollableNode()": "TAG 1",
      "getScrollResponder()": "OBJECT 2",
      "getNativeScrollRef()": "OBJECT 1",
      "findHostInstance_DEPRECATED()": "OBJECT 1",
      "_reactInternals": "PRESENT"
    },
    "getNativeScrollRef()": "OBJECT 1",
    "__internalInstanceHandle": {
      "objectId": 3,
      "findNodeHandle()": "ERROR",
      "findHostInstance_DEPRECATED()": "ERROR",
      "stateNode.node": {
        "objectId": 4,
        "findNodeHandle()": "ERROR",
        "findHostInstance_DEPRECATED()": "ERROR",
        "shadowNodeWrapper": "SHADOW_NODE_WRAPPER 1",
        "shadowNodeWrapperTag": "TAG 1"
      }
    },
    "findHostInstance_DEPRECATED()": "ERROR",
    "deepShadowNodeWrappersProps": {
      ".__internalInstanceHandle.stateNode.node": {
        "shadowNodeWrapper": "SHADOW_NODE_WRAPPER 1",
        "shadowNodeWrapperTag": "TAG 1"
      },
      ".getScrollResponder()._innerView.nativeInstance.__internalInstanceHandle.stateNode.node": {
        "shadowNodeWrapper": "SHADOW_NODE_WRAPPER 2",
        "shadowNodeWrapperTag": "TAG 2"
      }
    }
  },

  {
    "name": "SVG Path",
    "objectId": 1,
    "findNodeHandle()": "TAG 1",
    "getNativeScrollRef()": {
      "objectId": 2,
      "findNodeHandle()": "TAG 1",
      "__internalInstanceHandle": {
        "objectId": 3,
        "findNodeHandle()": "ERROR",
        "findHostInstance_DEPRECATED()": "ERROR",
        "stateNode.node": {
          "objectId": 4,
          "findNodeHandle()": "ERROR",
          "findHostInstance_DEPRECATED()": "ERROR",
          "shadowNodeWrapper": "SHADOW_NODE_WRAPPER 1",
          "shadowNodeWrapperTag": "TAG 1"
        }
      },
      "findHostInstance_DEPRECATED()": "ERROR"
    },
    "findHostInstance_DEPRECATED()": "OBJECT 2",
    "_reactInternals": "PRESENT",
    "deepShadowNodeWrappersProps": {
      ".root.__internalInstanceHandle.stateNode.node": {
        "shadowNodeWrapper": "SHADOW_NODE_WRAPPER 1",
        "shadowNodeWrapperTag": "TAG 1"
      }
    }
  }
]

Conclusions

  • findNodeHandle() always returns the correct handle on a ref
  • getScrollableNode() always returns a number handle and it's the correct handle (same as findNodeHandle())
  • findHostInstance_DEPRECATED() always throws on some components, i.e. View
  • getNativeScrollRef() always returns a result of findHostInstance_DEPRECATED() on a ref, if findHostInstance_DEPRECATED() on the ref doesn't throw (see ScrollView and FlatList) or an object with __internalInstanceHandle if it throws (see FlashList or SectionList).
  • shadowNodeWrapper is always obtained from __internalInstanceHandle.stateNode.node.
  • Some components have more than one ShadowNodeWrapper and more than one handle, but the second handle is never picked up with any methods.
  • findHostInstance_DEPRECATED() doesn't throw on a ref if ref has _reactInternals property.
  • getScrollRef() and getScrollResponder() methods aren't necessary to obtain the ShadowNodeWrapper.

Proposed solution:

  • To obtain a handle, simply call findNodeHandle on the ref.
  • To obtain a HostInstance, do the following:
    1. Check if the ref has __internalInstanceHandle prop. If it does, return it.
    2. Check if the ref has getNativeScrollRef() method. If it does, return getNativeScrollRef().__internalInstanceHandle.
    3. Check if the ref has _reactInternals prop. If it does, return findHostInstanceDeprecated().__internalInstanceHandle.
    4. Throw an error if 1. 2. and 3. were false.

Web results

Web logs

[
  {
    "name": "ActivityIndicator",
    "objectId": 1,
    "scrollTo()": "PRESENT"
  },

  {
    "name": "Button",
    "objectId": 1,
    "scrollTo()": "PRESENT"
  },

  {
    "name": "FlatList",
    "objectId": 1,
    "getScrollableNode()": "OBJECT 2",
    "getScrollResponder()": {
      "objectId": 3,
      "getScrollableNode()": "OBJECT 2",
      "getScrollResponder()": "OBJECT 3",
      "getNativeScrollRef()": "OBJECT 2",
      "scrollTo()": "PRESENT",
      "_reactInternals": "PRESENT"
    },
    "getNativeScrollRef()": {
      "objectId": 2,
      "getScrollableNode()": "OBJECT 2",
      "getScrollResponder()": "OBJECT 3",
      "getNativeScrollRef()": "OBJECT 2",
      "scrollTo()": "PRESENT"
    },
    "_reactInternals": "PRESENT"
  },

  {
    "name": "Image",
    "objectId": 1,
    "scrollTo()": "PRESENT"
  },

  {
    "name": "ImageBackground",
    "objectId": 1,
    "scrollTo()": "PRESENT"
  },

  {
    "name": "KeyboardAvoidingView",
    "objectId": 1,
    "_reactInternals": "PRESENT"
  },

  {
    "name": "Pressable",
    "objectId": 1,
    "scrollTo()": "PRESENT"
  },

  {
    "name": "RefreshControl",
    "objectId": 1,
    "scrollTo()": "PRESENT"
  },

  {
    "name": "ScrollView",
    "objectId": 1,
    "getScrollableNode()": "OBJECT 1",
    "getScrollResponder()": {
      "objectId": 2,
      "getScrollableNode()": "OBJECT 1",
      "getScrollResponder()": "OBJECT 2",
      "getNativeScrollRef()": "OBJECT 1",
      "scrollTo()": "PRESENT",
      "_reactInternals": "PRESENT"
    },
    "getNativeScrollRef()": "OBJECT 1",
    "scrollTo()": "PRESENT"
  },

  {
    "name": "SectionList",
    "objectId": 1,
    "getScrollableNode()": {
      "objectId": 2,
      "getScrollableNode()": "OBJECT 2",
      "getScrollResponder()": "OBJECT 3",
      "getNativeScrollRef()": "OBJECT 2",
      "scrollTo()": "PRESENT"
    },
    "getScrollResponder()": {
      "objectId": 3,
      "getScrollableNode()": "OBJECT 2",
      "getScrollResponder()": "OBJECT 3",
      "getNativeScrollRef()": "OBJECT 2",
      "scrollTo()": "PRESENT",
      "_reactInternals": "PRESENT"
    },
    "_reactInternals": "PRESENT"
  },

  {
    "name": "Switch",
    "objectId": 1,
    "scrollTo()": "PRESENT"
  },

  {
    "name": "Text",
    "objectId": 1,
    "scrollTo()": "PRESENT"
  },

  {
    "name": "TextInput",
    "objectId": 1,
    "scrollTo()": "PRESENT"
  },

  {
    "name": "TouchableHighlight",
    "objectId": 1,
    "scrollTo()": "PRESENT"
  },

  {
    "name": "TouchableOpacity",
    "objectId": 1,
    "scrollTo()": "PRESENT"
  },

  {
    "name": "TouchableWithoutFeedback",
    "objectId": 1,
    "scrollTo()": "PRESENT"
  },

  {
    "name": "VirtualizedList",
    "objectId": 1,
    "getScrollableNode()": {
      "objectId": 2,
      "getScrollableNode()": "OBJECT 2",
      "getScrollResponder()": "OBJECT 3",
      "getNativeScrollRef()": "OBJECT 2",
      "scrollTo()": "PRESENT"
    },
    "getScrollResponder()": {
      "objectId": 3,
      "getScrollableNode()": "OBJECT 2",
      "getScrollResponder()": "OBJECT 3",
      "getNativeScrollRef()": "OBJECT 2",
      "scrollTo()": "PRESENT",
      "_reactInternals": "PRESENT"
    },
    "getScrollRef()": "OBJECT 2",
    "_reactInternals": "PRESENT"
  },

  {
    "name": "View",
    "objectId": 1,
    "scrollTo()": "PRESENT"
  },

  {
    "name": "FlashList",
    "objectId": 1,
    "getScrollableNode()": "OBJECT 2",
    "getScrollResponder()": {
      "objectId": 3,
      "getScrollableNode()": "OBJECT 2",
      "getScrollResponder()": "OBJECT 3",
      "getNativeScrollRef()": "OBJECT 2",
      "scrollTo()": "PRESENT",
      "_reactInternals": "PRESENT"
    },
    "getNativeScrollRef()": {
      "objectId": 2,
      "getScrollableNode()": "OBJECT 2",
      "getScrollResponder()": "OBJECT 3",
      "getNativeScrollRef()": "OBJECT 2",
      "scrollTo()": "PRESENT"
    },
    "scrollTo()": "PRESENT"
  },

  {
    "name": "RNGHScrollView",
    "objectId": 1,
    "getScrollableNode()": "OBJECT 1",
    "getScrollResponder()": {
      "objectId": 2,
      "getScrollableNode()": "OBJECT 1",
      "getScrollResponder()": "OBJECT 2",
      "getNativeScrollRef()": "OBJECT 1",
      "scrollTo()": "PRESENT",
      "_reactInternals": "PRESENT"
    },
    "getNativeScrollRef()": "OBJECT 1",
    "scrollTo()": "PRESENT"
  },

  {
    "name": "SVG Path",
    "objectId": 1,
    "_reactInternals": "PRESENT"
  }
]

Web

  • getScrollableNode() returns an actionable ref (i.e. - one that has scrollTo method). On components like SectionList this is the way of obtaining the actionable ref.
  • getScrollableNode() is not defined on every list component, i.e. SectionList.
  • getNativeScrollRef() always provides an actionable ref if defined.
  • findNodeHandle is an identity function.

Proposed solution:

  • To obtain the actionable ref, do the following:
    1. Check if the ref has getScrollableNode() method. If it does, return getScrollableNode().
    2. Check if the ref has getNativeScrollRef() method. If it does, return getNativeScrollRef().
    3. Return ref if 1. and 2. were false.

Test plan

  • Check Web implementation
  • Check SVG components
  • Check Gesture Handler components
  • Add runtime test suite
  • Trust me bro

Copy link
Member

@tomekzaw tomekzaw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM but let's ask about @piaskowyk's opinion prior to merging as he has touched these files recently as well

@joaquinvaz
Copy link

@piaskowyk Please can you check this? we need it here

gorhom/react-native-bottom-sheet#2450 (comment)

Thanks!

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

useAnimatedRef with createAnimatedComponent(SectionList) will make app crash

3 participants