Stencil version:
@stencil/[email protected]
I'm submitting a:
[ ] bug report
[ ] feature request
[ ] support request => Please do not submit support requests here, use one of these channels: https://stencil-worldwide.herokuapp.com/ or https://forum.ionicframework.com/
Current behavior:
Sometimes, it's useful to pass a function as the first and only child, as is the case with @ionic/state-tunnel.
I'm implementing my own state tunnel. Writing code like this:
import { Component, Prop, h } from "@stencil/core";
@Component({
tag: "my-component",
styleUrl: "my-component.css",
shadow: true
})
export class MyComponent {
render() {
return (
<my-other-component>
{() => {
return "foo";
}}
</my-other-component>
);
}
}
Results in the following console error:
[STENCIL-DEV-MODE] vNode passed as children has unexpected type.
Make sure it's using the correct h() function.
Empty objects can also be the cause, look for JSX comments that became objects.
Expected behavior:
To my understanding, a function is valid child type. No error should be logged.
Steps to reproduce:
Demo repo: https://github.com/petermikitsh/stencil-function-children
What is the expected result? Having this function available to the child inside the slotted children without the scope of the main one? I would use redux or state tunnel and well seperate things. If dynamic function passdowns are needed eventEmitters or simple Props could handle that too. One could also think about having dynamic functions stored in redux, for a crazy evolving function pool to be executed. Render() should only produce JSX by my understanding.
Render() should only produce JSX by my understanding.
@stanley85 Agreed. The render function should always return JSX. But JSX is just syntactic sugar for calling the pragma function: h(componentTagName, props, children). Using our example above, here is our "compiled" JSX:
import { Component, h } from "@stencil/core";
@Component({
tag: "my-component",
})
export class MyComponent {
render() {
return h("my-other-component", null, () => {
return "foo";
});
}
This is valid JSX.
What is the expected result?
The code runs fine. @stencil/core prints an error message that suggests that Stencil is having a problem with a child being Function type. But that's not the case.
...Having this function available to the child inside the slotted children without the scope of the main one?
In @ionic/state-tunnel, the exported Consumer is actually a functional component. The function is called each time the tunneled state changes. So, there are valid use cases for passing in a function as a child to a component.
Now I have learned something - what is your usecase if I may ask? We are using redux by now to have a state cosumed by our application and subs.
Related: #1969.
I am confused why would you pass a function like that?
@manucorporat It's how it's done in the stencil-state-tunnel project. See 3. Place your state consumption points.
Another project that uses the pattern is react-motion.
This article describes the advantages of passing a function as child components.
It is also easier to pass a parent function as a prop and invoke it from the child than doing the whole Event thing.