Subscribe on changes!

When `render` directly returns `a custom object`, will throw an uncaught TypeError.

avatar
Jul 13th 2023

Vue version

3.3.4

Link to minimal reproduction

https://play.vuejs.org/#eNp9U01v2zAM/SuCLk6BzMbWy5A5Qbu1hw3YOnTFTrooNpM6lSVBkr0Uhv/7KPojKVDkYMgk36PIJ7Ljt9ambQN8xXNfuMoG5iE0limp92vBgxd8I3RVW+MC65iDHevZzpmaJUhL5tAd1Gb0p1k0ki9CC10Y7QMrZZCPyFxHfi7162aR6KbegkuuzmB48x0iPz1sDwhdXLH1hnVCs4mftlI1gKGOaVnDiiXxSJZM7tH4+Jn1mCx+U0IHLTjKeTnfVMxIz7NBCmwcjQC1VTIAWozl1Gf7oTYlKNRnzCR4RmAElFW7mfqtPFt13Wj1fZ7FIKG2TQhGs5tCVcUL5jlrHQVHiwXDzPaQZwNyZLl4zTv0U6PIHowzZp7NPfAlPimKs6v26cEbje9OighemNpWCtyDDRWKJ/hq0CrGpFLm3w/yBdfAcvIXz1C8vOM/+GP0Cf7bgQfXguBzLEi3hzCE7//8giP+z0GUtVGIvhB8BG9UE2scYF8bXWLZZziq9juNZaX3T/7+GED7qalYaET2hBccp/jbhdZP5V6n18TDGUEV4xykwaN+825YZ6x/MrchuJ/Szmtygzdk/lk6KOOAzfASdpWmu40GHd6sFc2w0HAkLCJlo+g8ZyyoyHETaOWoJSpj7oAG9W+cc3Sx8Grx1I1SsY9JBNr4BfGuJp5Dn9Pj0lAoPaXC8gZuH9eX9/8BOFdwUg==

Steps to reproduce

click set to obj button will throw warning:

Invalid VNode type:(undefined)
 at <DemomodelValue=[object Object]onUpdate:modelValue=fn>
 at <Repl>

image

and then click revert button, will throw uncaught TypeError:

Uncaught (in promise): Cannot read properties of undefined (reading 'parentNode')

image

What is expected?

Whether it's warning against directly returning objects during development, catching that exception, or providing clearer warning instructions in the documentation, I would prefer it to be traceable rather than throwing an error in an unrelated place.

And, if possible, could the returned object be serialized? But I think this might bring more trouble, so maybe having a warning is sufficient.

By the way, about the documentation, I have reviewed the documentation, and it mentions that you can also return strings or arrays. However, it does not specify the consequences of returning an object. image

What is actually happening?

I think that it is here where there is no strict validation whether child is necessarily a VNode. https://github.com/vuejs/core/blob/37a14a5dae9999bbe684c6de400afc63658ffe90/packages/runtime-core/src/vnode.ts#L746-L750


I add a simple test in rendererComponent:

  test('render return object', async () => {
    const root = nodeOps.createElement('div')
    const App = {
      render() {
        return {info:'hi'};
      }
    }
    render(h(App), root)
    expect(serializeInner(root)).toBe(`[object Object]`)
  })

child will be Object {info : "hi"}, and then it will be cloned as a VNode. I think the starting point is here, causing a series of operations afterwards that lead to various kinds of exceptions being thrown.

System Info

No response

Any additional comments?

This is the process where my issue occurs:

When I was developing a component using TSX, I wrote this piece of code:

<td class="m-td">{slot ? slot(...) : data}</td>

Due to the coding habit of SFC, I didn't realize that using an object as data was incorrect. However, when I used the component, my data(in the code) changed from a string to an object, and that's when the exception was thrown.

image

However, this exception completely prevents me from pinpointing the error, so I have to narrow down the scope gradually, which consumes some time.

And as you can see, in my various actions, it gives various warnings or errors, but it seems unrelated to the current behavior scenario.

So, I think it might be more user-friendly to add a conditional check and warning in

https://github.com/vuejs/core/blob/37a14a5dae9999bbe684c6de400afc63658ffe90/packages/runtime-core/src/vnode.ts#L746-L750

or directly check the __v_isVNode property of the child to route non-VNodes to the last else case https://github.com/vuejs/core/blob/37a14a5dae9999bbe684c6de400afc63658ffe90/packages/runtime-core/src/vnode.ts#L750-L753 These approaches would provide a more friendly solution, relatively speaking.

If possible, I would be happy to submit a pull request to fix this issue.

avatar
Jul 14th 2023

IMO, If the user returns a non-VNode, an error should be reported. Because Vue can't handle it. There is no point in giving warnings, and many people don't really care about warnings.