updateChildren(children) {
    const oldDict = this._childrenDict || null
    let newDict = this._childrenDict = null
    const orderedChildKeys = this._orderedChildKeys
    orderedChildKeys.length = 0

    if (children) {
      // Allow single child without wrapper array
      if (!Array.isArray(children)) {
        TEMP_ARRAY[0] = children
        children = TEMP_ARRAY
      }

      for (let i = 0, len = children.length; i < len; i++) {
        let childDesc = children[i]
        if (!childDesc) continue //child members can be null
        if (!newDict) {
          newDict = this._childrenDict = Object.create(null)
        }

        // Handle child descriptors defined via a JSX->React.createElement() transforms (ReactElement objects)
        const isJSX = isReactElement(childDesc)
        let propsObj = isJSX ? childDesc.props : childDesc
        let facadeClass = isJSX ? childDesc.type : childDesc.facade

        // Find this child's key; if not specified by the author, build one from the facade class name
        let key = childDesc.key
        if (!key) {
          let j = 0
          do {
            key = `auto:${facadeClass.name}:${j++}`
          } while (newDict[key])
        }

        // Some basic validation in dev mode
        if (process.env.NODE_ENV !== 'production') {
          if (typeof facadeClass !== 'function') {
            throw new Error('All scene objects must have a "facade" property pointing to a class/constructor')
          }
        }
        if (newDict[key]) {
          console.warn(`Duplicate key in children: ${key}`)
          while(newDict[key]) {
            key += '|dupe'
          }
        }

        // If a transition/animation is present, upgrade the class to a Animatable class on demand.
        // NOTE: changing between animatable/non-animatable results in a full teardown/recreation
        // of this instance *and its entire subtree*, so try to avoid that by always including the `transition`
        // definition if the object is expected to ever need transitions, even if it's temporarily empty.
        let transition = propsObj.transition
        let animation = propsObj.animation
        if (transition || animation || propsObj.exitAnimation) {
          facadeClass = extendAsAnimatable(facadeClass)
        }

        // Same for pointer states
        if (propsObj.pointerStates) {
          facadeClass = extendAsPointerStatesAware(facadeClass)
        }

        // If we have an old instance with the same key and class, update it, otherwise instantiate a new one
        let oldImpl = oldDict && oldDict[key]
        let newImpl
        if (oldImpl && oldImpl.constructor === facadeClass) {
          newImpl = oldImpl
        } else {
          // If swapping instance need to destroy the old before creating the new, e.g. for `ref` call ordering
          if (oldImpl) oldImpl.destructor()
          newImpl = new facadeClass(this)
        }
        //always set transition/animation before any other props
        newImpl.transition = transition
        newImpl.animation = animation
        for (let prop in propsObj) {
          if (propsObj.hasOwnProperty(prop) && !Facade.isSpecialDescriptorProperty(prop)) {
            newImpl[prop] = propsObj[prop]
          }
        }
        newDict[key] = newImpl
        orderedChildKeys.push(key)
        newImpl.afterUpdate()
      }
    }

    // Destroy all old child instances that were not reused or replaced
    if (oldDict) {
      for (let key in oldDict) {
        if (!newDict || !newDict[key]) {
          oldDict[key].destructor()
        }
      }
    }
  }
Override to selectively prevent traversing to child nodes on `afterUpdate`, for
potential performance gain.
@returns {boolean}