Skip to content

Conversation

RedHatter
Copy link
Contributor

@RedHatter RedHatter commented Apr 2, 2025

The new tree patch expects the node.type of class components to be of type "object" however this is not the case.

An example class component node might look like

{
    $$typeof:  Symbol(react.element)
    "key": null,
    "ref": null,
    "props": {},
    "type": class extends
    "_owner": null
}

Where node.type is a component class. Since classes in javascript are of type "function"

class HelloWorld extends Component {
  render() {
    return <h1>Hello world!</h1>;
  }
}

assert(typeof HelloWorld === 'function')

the tree patcher fails to detect and wrap the class component.

An alternative fix could be to remove the switch and test the prototype first

    if (node[prop]?.prototype?.render) {
        // Class component
        // TODO handle patching custom methods
        wrapReactClass(node);
        const patch = afterPatch(node[prop].prototype, 'render', steps[step + 1] ? createStepHandler(handler, steps, step + 1, caches, logger) : handler);
        loggingEnabled && logger.debug('Patched class component', patch);
    } else if (typeof node?.[prop] === 'object') {
        loggingEnabled && logger.debug('Patching forwardref/memo');
        wrapReactType(node, prop);
        // Step down the object
        patchComponent(node[prop], handler, steps, step, caches, logger, node[prop]?.render ? 'render' : 'type'); 
    } else {
        // Function component
        const patch = afterPatch(node, prop, steps[step + 1] ? createStepHandler(handler, steps, step + 1, caches, logger) : handler);
        loggingEnabled && logger.debug('Patched a function component', patch);
    }

@RedHatter
Copy link
Contributor Author

RedHatter commented Apr 2, 2025

Included below is a snipit demonstrating tree patcher failing to patch a class component.

  routerHook.addPatch("/library/app/:appid", (props: { path: string; children: ReactElement }) => {
    afterPatch(
      props.children.props,
      "renderFunc",
      createReactTreePatcher(
        [
          (tree) => tree.props.children,
          (tree) => tree.props.children?.[1]?.props.children.props.children.find((child: any) => "children" in child.props).props.children,
        ],
        (_: Array<Record<string, unknown>>, tree?: ReactElement) => {
          return tree
        }
      ),
    )

    return props
  })

This causes a crash with the error message TypeError: Class constructor se cannot be invoked without 'new'.

@AAGaming00 AAGaming00 self-requested a review April 2, 2025 02:46
@AAGaming00
Copy link
Member

Very interesting, ill test this as soon as I have a chance

Probably an oversight I made as all of the patcher was probably made at like 3 am sleep deprived

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants