Per #2645250-179: [META] Start using reactive declarative JS programming for some new core admin UIs, this is a child issue to discuss one factor in a vdom library that might be important to us.
Problem/Motivation
- React has a limitation where a component's render function can only return a single root element. Therefore, I assume that libraries designed for React's API, such as Preact and Inferno, have the same limitation.
- Vue has the same limitation.
- Mithril does not have this limitation. See also the last code block in this example.
Drupal does occasionally return non-single-node fragments from various places, and when code is required to add an extra <div> wrapper to force it into a single node, problems arise. #736066: ajax.js insert command sometimes wraps content in a div, potentially producing invalid HTML and other bugs is an example of a 7 year old issue where we're still struggling with this.
If we end up picking a library that has a single-root-node-per-component limitation, are we willing to accept the consequences of occasional wrapper tags polluting a theme's desired markup structure?
Proposed resolution
?
Remaining tasks
Discuss.
Comments
Comment #2
benjy commentedI'm not sure I fully get this, if you are handwriting React components, you need a top-level wrapper, React developers would know this. Unlike the issue referenced (#736066) we'll never be generating the initial HTML on the server from Drupal?
Drupal generating HTML that we intend for React to then manage actually seems to me like it would be way more problematic.
Comment #3
psteeleidem commentedFWIW, with the latest release of Marko.js there is no limitation on the number of root nodes and no extra DOM nodes that will pollute the DOM will be added. A UI component can render a single DOM node, multiple DOM nodes, no DOM nodes, only text nodes, etc. Also, there is no limitation regardless of whether or not a UI component is rendered on the server (under Node.js) or in the browser.
Comment #4
Anonymous (not verified) commentedAnd Polymer, and Aurelia... they all have this limitation.
But I don't see how that will be an issue since the component will be fully rendered on the first page load and on ajax request, I would assume, we would only return state changes(drupalSettings --> Flux) which would get re-rendered by the component(that's where the reactivity comes in), instead of the old way of replacing pure HTML.
I would assume each page component would be registered in the drupalSettings' "components" store and it would react to changes made to the store as in any other application.
Comment #5
dawehnerI can't judge whether this missing feature is an actual problem. Can't you write some wrapper components which returns multiple elements? The resulting HTML should be the same.
Note: As of react 0.16 this is no longer a limitation: https://github.com/facebook/react/issues/2127#issuecomment-318202889
On the other hand, this might not be implemented by the *react alternatives.
Comment #6
effulgentsia commentedComment #7
GrandmaGlassesRopeMan@effulgentsia as of react 16 this is no longer an issue.What @dawehner said.Comment #8
effulgentsia commentedIt's still an issue for Vue.js though. Hence the reparenting of this in #6.
Comment #9
alexdoronin commentedReact — https://medium.com/@gajus/using-react-v16-to-create-self-destructing-com...
Comment #10
alexdoronin commentedFor Vue — maybe some workarounds with "functional components" https://jsfiddle.net/of6z0nu4/
(https://vuejs.org/v2/guide/render-function.html#Functional-Components).
Comment #11
effulgentsia commentedRe #10, wow, that's cool! The
functional: trueis required though. Do you know if this is a by-design feature that functional components are allowed to do this? https://vuejs.org/v2/guide/migration.html#Fragment-Instances-removed does not mention it, nor can I find any other Vue docs that do. https://github.com/vuejs/vue/issues/5961#issuecomment-310895399 mentions it, but that comment is not from a maintainer, and the maintainer's reply is simply that it's on the roadmap but with no projected timeframe or issue link. He neither confirmed nor denied the comment about functional components having the escape hatch. If the escape hatch wasn't intentional, then I'm concerned it might get removed in a future release prior to full support across all types of components getting added.Comment #12
effulgentsia commentedAlso, React 16 allows returning bare text (e.g.,
return 'one';) and top-level text nodes alongside sibling elements (e.g.,return [h('div', {}, 'one'), 'two'];). Whereas for Vue, the example in #10 seems to only work for an array of elements (no top-level text nodes allowed).Comment #13
alexdoronin commentedRe: #11
Unfortunately I can't clarify the situation with functional components in Vue. I heard about this approach only from non-maintainers.
Comment #14
dawehnerIt would be nice to document instances of that. Maybe there are common patterns to be seen.
Comment #21
jungle> In 3.x, components now can have multiple root nodes!
https://v3.vuejs.org/guide/migration/fragments.html#_3-x-syntax
Comment #22
effulgentsia commentedYep! This is no longer a differentiator between React and Vue, so closing the issue.
Per #3170260: Decoupled Menus Initiative, the current plan is to build some components for both React and Vue, and to publish them on npm, thereby postponing by as long as we can the need to make either one a hard dependency of Drupal core.
However, if/when there's a compelling reason to make one or both of them a hard dependency, we can discuss doing so. #3201871: Document benefits/drawbacks of adding Vue as a core JS library is the current place to discuss that about Vue, and so far that hasn't crossed the threshold, because the Backbone replacement issues look like they can happen well enough with vanilla JS instead.