Vue.js documentation “Essentials” section ended with a page on “Component Basics”. That lead to the next section “Components In-Depth” covering more details on how and when to use Vue.js components and how they interact with other components in the app. After reading the section, a few items caught my attention that may or may not be significant once I start getting hands-on with Vue.
Names for Vue.js components are PascalCase by convention but that has problems with using them in HTML attributes that are liable to coerce everything to lowercase. The same problem applies to Vue.js events which are camelCase by convention. Vue.js includes magic to look at equivalent kebab-case names. I guess it solves the problem but seems like a source for future problems. What if multiple cased versions exist in code, which one runs first?
Name collisions could also happen due to a feature called “fallthrough attributes”. A component with its own “click” could have another “click” fall through from above. Which one has priority? A declared emitted “click” handler would override native “click”. A fallthrough “click” and an emitted “click” would… both be called? Wild.
I like that Vue.js works to magically fix up these kinds of problems, but I’m uncomfortable magic renaming mechanisms exist. Historically they were a high risk for bugs.
Props and Events
Props are intended to be one-way, from parent to child. But because it’s valid to pass objects, a child can modify those object instance and potentially change parent state. For performance reasons, Vue doesn’t try to detect or prevent such “deep change”. Documentation boils down to “Don’t do that” though it did describe a few potential scenarios and their workarounds. The right way for a child to communicate with parent is with emitted events, which are raised only on its direct parent.
Props go from parent to immediate child, emitted events are raised from child to immediate parent. Going beyond that (communicating across multiple layers in the hierarchy) could get messy. I saw mention for one mechanism called State Management, which will be covered in the “Scaling Up” section. There’s also the Provide/Inject mechanism, which isn’t exactly the same as Angular services but has a few similarities. To make them properly reactive values require
computed() which is normally just for Vue.js Composition API. To read more about
computed(), we are instructed to go back and read certain documentation sections while set to Composition API and not Options API.
Props can have default values when not assigned by parent and/or marked as “required”. To help keep objects well-behaved, we can validate values for props to ensure information coming in to a component is within expected range. We can also validate events, which isn’t a mechanism that shows up very often. Usually, events going out are assumed to be within expected range because it was generated within that component. Or maybe I’m misunderstanding the Vue.js mechanism.
As mentioned earlier (in the context of state management) there’s an entire section dedicated to scaling up to larger and more complex projects. But we do get a preview of several mechanisms because they rightly belong in “Components In-Depth”
One item I had wondered about upon learning v-model was how that would work across component boundaries. The short version: Either (1) bind to a native input component inside the custom component template, or (2) bind to a writable computed value with getter and setter.
I think I have a good grasp of slots, but not scoped slots. It took me three readings to understand it is a (convoluted at first glance) way for information to cross parent/child component boundary. This will definitely take several rounds of hands-on practice (and painful debugging sessions) to master.
Symbols keys were brought up as a way to avoid Provide/Inject naming ambiguity in large projects because they potentially have global scope. This is the first I remember seeing symbol keys, I expect to get more information about it elsewhere in documentation.
Vue.js apps that grow big enough to worry about download size can split components off to be loaded asynchronously on demand. Vite recognizes this mechanism as a breakpoint for bundling purposes. I have yet to come across its Angular counterpart. Possibly lazy loading?
Building and using components are great, but they are not the end of the Vue story on code reusability.