Kaynağa Gözat

fix: instances re-instancing when not needed (#374)

* fix: instances re-instancing when not needed

* chore: remove console

* chore: minor changes concerning re-instancing

---------

Co-authored-by: Tino Koch <tinoooo@users.noreply.github.com>
Alvaro Saburido 1 yıl önce
ebeveyn
işleme
f2ae46bebd
2 değiştirilmiş dosya ile 22 ekleme ve 2 silme
  1. 10 2
      src/core/nodeOps.ts
  2. 12 0
      src/utils/index.ts

+ 10 - 2
src/core/nodeOps.ts

@@ -67,6 +67,13 @@ export const nodeOps: RendererOptions<TresObject, TresObject> = {
       if (props?.geometry?.isBufferGeometry) (instance as TresObject3D).userData.tres__geometryViaProp = true
     }
 
+    // Since THREE instances properties are not consistent, (Orbit Controls doesn't have a `type` property) 
+    // we take the tag name and we save it on the userData for later use in the re-instancing process.
+    instance.userData = {
+      ...instance.userData,
+      tres__name: name
+    }
+
     return instance
   },
   insert(child, parent) {
@@ -188,9 +195,10 @@ export const nodeOps: RendererOptions<TresObject, TresObject> = {
         const prevNode = node as TresObject3D
         const prevArgs = _prevValue ?? []
         const args = nextValue ?? []
+        const instanceName = node.userData.tres__name || node.type
 
-        if (node.type && !deepArrayEqual(prevArgs, args)) {
-          root = Object.assign(prevNode, new catalogue.value[node.type](...nextValue))
+        if (instanceName && prevArgs.length && !deepArrayEqual(prevArgs, args)) {
+          root = Object.assign(prevNode, new catalogue.value[instanceName](...nextValue))
         }
         return
       }

+ 12 - 0
src/utils/index.ts

@@ -26,6 +26,10 @@ const HTML_TAGS =
 
 export const isHTMLTag = /*#__PURE__*/ makeMap(HTML_TAGS)
 
+export function isDOMElement(obj: any): obj is HTMLElement {
+  return obj && obj.nodeType === 1;
+}
+
 export function kebabToCamel(str: string) {
   return str.replace(/-([a-z])/g, (_, c) => c.toUpperCase())
 }
@@ -77,6 +81,14 @@ export const set = (obj: any, path: string | string[], value: any): void => {
 
 
 export function deepEqual(a: any, b: any): boolean {
+  if (isDOMElement(a) && isDOMElement(b)) {
+    const attrsA = a.attributes;
+    const attrsB = b.attributes;
+
+    if (attrsA.length !== attrsB.length) return false;
+
+    return Array.from(attrsA).every(({ name, value }) => b.getAttribute(name) === value);
+  }
   // If both are primitives, return true if they are equal
   if (a === b) return true;