RFC: Self reference in recursive components #832
ubugeeei
started this conversation in
RFC Discussions
Replies: 2 comments
-
|
这是来自QQ邮箱的自动回复邮件。
我已经收到了你的来信,我会尽快回复。
|
Beta Was this translation helpful? Give feedback.
0 replies
-
|
Seems simple enough to have it. For me, I wished a new proposal could improve the TS at the same time. |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Pull Request: #833
Summary
Introduce a compiler-reserved
<Self>template tag that renders the current component. This allows recursive components to refer to themselves without depending on the component'snameoption or an SFC filename-derived inferred name.Basic example
If
TreeNode.vueis later renamed toNestedListItem.vue, the recursive reference does not need to be renamed because it is no longer expressed as<TreeNode>.Motivation
Today, a recursive component must refer to itself by name. With the Options API, this usually means declaring a
nameoption and using that name in the template:With SFCs, Vue can infer a component's name from the filename, so
TreeNode.vuecan recursively reference itself as<TreeNode />. This avoids an explicitnameoption, but it still couples the recursive reference to a name derived from the file path.That coupling creates a maintenance hazard:
nameis also used for DevTools, warning traces, and<KeepAlive>include / exclude matching, but those display and matching concerns are separate from the semantic intent to render "this component again."Recursive components are common for trees, nested menus, threaded comments, document outlines, AST viewers, and schema-driven renderers. In these cases, the intent is local and structural: render another instance of the same component. The template should be able to express that intent directly.
Detailed design
<Self>in templates<Self>is a special component tag recognized by Vue's template compiler. It always resolves to the component currently being rendered by the template in which the tag appears.The reserved spelling is exactly
<Self>in case-preserving templates such as SFC templates and string templates. The lowercase<self>spelling is not special in those templates.<Self>behaves like a normal component invocation:v-if,v-for,v-show, and slots work the same way as they do on any component tag.refplaced on<Self>refers to the child instance created by that tag, not the parent instance.For example:
Resolution semantics
<Self>is reserved by the compiler and has higher priority than local component bindings, explicit component registrations, and global component registrations.This means the following template renders the current component, not the imported
Selfbinding:If an imported or locally registered component named
Selfis needed, it should be renamed and used through that other name:The compiler should emit a development warning when a component binding named
Selfis present in the same template scope, because the binding will be shadowed by the reserved tag.Compiler output
The compiler can lower
<Self>to an internal helper that resolves the current component type from the current rendering instance.Conceptually:
The exact helper name is not part of the public API. The important behavior is that the rendered vnode uses the same component definition as the component whose template contains
<Self>.The same lowering should be supported by both the DOM compiler and the SSR compiler so that client-side rendering and server-side rendering produce equivalent component trees.
Relationship with component
nameThis proposal does not remove or change component name inference.
The
nameoption and SFC filename-based inferred names remain useful for:<KeepAlive>include / exclude matching.<Self>only provides a name-independent way to express recursive self-reference in templates.Supported authoring forms
<Self>is intended to work in normal SFC templates, including SFCs using<script setup>:It should also work in templates authored with the Options API:
Render functions and JSX are out of scope for this proposal because they can already close over the current component definition explicitly when needed.
Tooling
Vue-aware tooling should treat
<Self>as a built-in special component:eslint-plugin-vueshould be able to recognize it as a valid component tag.Drawbacks
Selfbecomes a reserved component tag. Existing applications that intentionally use a local or global component namedSelfwould need to rename that component or render it dynamically.The feature adds compiler and tooling complexity for a relatively small ergonomic improvement. The implementation is likely modest, but support needs to be consistent across the SFC compiler, runtime compiler, SSR compiler, language tools, and lint rules.
The feature introduces another special template tag. Users need to learn that
<Self>is not imported, registered, or derived from the filename.It does not eliminate all uses of component names. Components may still need names for DevTools, warning traces, and
<KeepAlive>matching.Alternatives
Keep relying on
nameor filename inferenceThis is the current behavior. It avoids adding a new special tag, but keeps recursive self-reference coupled to component names.
Use
defineOptions({ name })defineOptions()can make the component name explicit in<script setup>, but the template still needs to repeat the same name:This is clear, but it keeps two declarations in sync.
Use a compiler macro
A macro such as
defineSelf()could expose the current component as a binding:This avoids reserving a tag, but it is more verbose and pushes a purely template-level concern into the script block.
Rely on lint rules and rename tooling
Tooling could warn when a recursive tag no longer matches the component filename or explicit name. This would reduce mistakes, but it would not remove the underlying coupling.
Adoption strategy
This is an additive feature. Existing recursive components continue to work unchanged.
Developers can adopt
<Self>incrementally in recursive components:A codemod could be provided for simple SFC cases where a component recursively references the inferred filename or explicit
name, and where no local binding conflict exists. Because component resolution can involve local and global registrations, such a codemod should be conservative.Documentation should update the recursive component sections to recommend
<Self>when the intent is to render another instance of the current component, while documenting thatnameremains relevant for diagnostics and<KeepAlive>.Unresolved questions
Should
<Self>be supported in in-DOM templates? Browser HTML parsing lowercases tag names before Vue sees them, so supporting in-DOM templates would likely require also reserving<self>, which has a higher compatibility risk.Should Vue expose a public render-function helper for the same concept, or should this remain a template-only feature?
Should the compiler warn, error, or silently shadow when a local binding named
Selfexists?Beta Was this translation helpful? Give feedback.
All reactions