RosettaJS: Comparativas de Vue, React y Angular

Component Communication

Two-Way Binding Between Components

Two-way binding between components keeps a value synchronized between a parent and child component, allowing both to participate in updating it.

Example

Updating the number of items in a cart from a reusable selector.

VuedefineModel + v-model

<script setup lang="ts">
import { ref } from 'vue'
import QuantitySelector from './QuantitySelector.vue'

const quantity = ref(1)
</script>

<template>
  <p>Items in cart: {{ quantity }}</p>
  <QuantitySelector v-model="quantity" />
</template>
// QuantitySelector.vue
<script setup lang="ts">
const quantity = defineModel<number>({ required: true })

function increment() {
  quantity.value += 1
}
</script>

<template>
  <button @click="increment">Add one</button>
</template>

The child declares defineModel(), which creates a model prop it can update. The parent binds it with v-model.

Reactvalue + onChange

import { useState } from 'react'
import { QuantitySelector } from './QuantitySelector'

function App() {
  const [quantity, setQuantity] = useState(1)

  return (
    <>
      <p>Items in cart: {quantity}</p>
      <QuantitySelector value={quantity} onChange={setQuantity} />
    </>
  )
}
// QuantitySelector.tsx
type QuantitySelectorProps = {
  value: number
  onChange: (value: number) => void
}

export function QuantitySelector({
  value,
  onChange,
}: QuantitySelectorProps) {
  return (
    <button onClick={() => onChange(value + 1)}>Add one</button>
  )
}

The parent keeps the state and passes the value along with a function for the child to request changes.

Angularmodel() + [(...)]

import { Component, signal } from '@angular/core'
import { QuantitySelectorComponent } from './quantity-selector.component'

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [QuantitySelectorComponent],
  template: `
    <p>Items in cart: {{ quantity() }}</p>
    <app-quantity-selector [(quantity)]="quantity" />
  `,
})
export class AppComponent {
  quantity = signal(1)
}
// quantity-selector.component.ts
import { Component, model } from '@angular/core'

@Component({
  selector: 'app-quantity-selector',
  standalone: true,
  template: `
    <button (click)="increment()">Add one</button>
  `,
})
export class QuantitySelectorComponent {
  quantity = model.required<number>()

  increment() {
    this.quantity.update((value) => value + 1)
  }
}

The child declares model() and the parent creates a two-way binding with [(quantity)].