3👍
You should avoid calling a child’s method via its $ref
, as it has severe disadvantages:
A. It’s a form of DOM manipulation
Simply put, this is the way we used to do things in jQuery.
In Vue, state/data drives change and you leave DOM rendering, updating and optimisation to Vue. Not because it’s not possible otherwise, but because it affects development and maintenance costs in direct proportion with the app’s complexity and size.
Calling a child component method from the parent means the change cannot be performed unless the child is in DOM, whereas when the parent changes the data directly it doesn’t need to worry about the child being rendered.
B. It’s a form of tight coupling and it breaks component isolation
Once you start allowing outer components calling a component’s methods you severe limit your refactoring capabilities, making both future changes and testing more complex (changing the child’s method might imply changes in every component using its method and possibly their tests). You increase the costs of maintenance without benefit.
Last, but not least, breaking isolation increases debugging and optimisation costs.
In a real-world scenario, you should ask other questions before asking the current one:
- do you need a parent/child relation there?
- can you refactor so that one of them doesn’t need to perform the change, ever?
- if both need to be able to make the change and they need to stay in sync, is it possible to move the method into a composable/helper function, where it would be imported from into each parent and child and then use
v-model
to keep data in sync?
In most (if not all) cases, answering the above questions would solve the problem before you are in the position to ask the current one.
As a general rule, you should limit coupling. In layman’s terms, you want the child to know as little as possible about the parent and the parent to know as little as possible about the child. When they do need to inform each other, limit the surface between their communication and use a well established pattern (e.g: v-model
if the child needs to inform the parent, props
otherwise).
When you can’t achieve the desired functionality without using a custom pattern, consider using a store or refactor to achieve encapsulation/isolation.
I can’t stress enough how big an impact this rule has on speed of development and, ultimately, on development costs, as the maintenance-free app doesn’t exist. It’s a myth. Every real-world app needs change in some shape of form and the above rule deeply impacts the time and effort needed to change, test, debug and optimise your apps.
2👍
If it’s something as simple as Label
which has no logic at all, use Component1.
. Because inserting unneded logic into basically stateless components is bad design
If it’s something as advanced as Dialog
which has a lot of logic and exposed functions, use Component2.
. Because if the componend is often created by script and has tens of exposed functions there is no other choice.
If it’s something in-between such as Toggle
, use two-way bindings
. Because if you need two-way binding, you use two-way binding.
<script setup lang="ts">
import { useVModel } from '@vueuse/core'
const props = defineProps<{
on: string
off: string
modelValue: string
}>()
const emit = defineEmits(['update:modelValue'])
const val = useVModel(props, 'modelValue', emit)
const defaultText = 'Off';
</script>
<template>
<div @click="val = !val">
{{ val ? on ?? '[on]' : off ?? 'off' }}
</div>
</template>
1👍
I think this is opinion based question and My answer would be "It totally depends on the requirement"
.
I know just for a demo purpose you created a toggle scenario and based on that scenario, first approach is a good one and proficient.
Instead of listing advantages/disadvantages, Let me explain the use case of both the approaches with the example :
Approach 1 : Using of props/events to communicate between the components.
If you have to just pass some data from parent to make decisions based on the passed param then you should go with this approach and this is the best practice to do that.
Approach 2 : Expose and invoke the child component method using ref
from parent component.
If you have to perform some logic in the child component by triggering an event in parent then I think this is a good approach to follow.