Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
higuaifan opened this issue Jul 13, 2023 · 1 comment

Comments

@higuaifan
Copy link

higuaifan commented Jul 13, 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.

} else if (typeof child === 'object') {
// already vnode, this should be the most common since compiled templates
// always produce all-vnode children arrays
return cloneIfMounted(child)
} else {


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

} else if (typeof child === 'object') {
// already vnode, this should be the most common since compiled templates
// always produce all-vnode children arrays
return cloneIfMounted(child)
} else {

or directly check the __v_isVNode property of the child to route non-VNodes to the last else case

} else {
// strings and numbers
return createVNode(Text, null, String(child))
}

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.

@edison1105
Copy link
Member

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
2 participants