React 和 Vue3 在事件传递的区别

最近用React19写了一个笔记应用,发现React和Vue3 在 事件传递 方式上不一样:

React :父组件定义方法,作为 props 传递给子组件,子组件在合适的时候调用这些方法(由父组件控制逻辑)

Vue3:子组件使用 defineEmits 触发事件,父组件监听事件并执行对应的回调函数(由子组件通知父组件)

最近写的笔记应用,我们以这个搜索组件来举例React和Vue的区别

React事件传递方式

在React中,父组件通过props(属性)向子组件传递数据和事件处理函数,使得子组件能够与父组件通信。我们以上面截图的搜索框组件为例,其中父组件传递了多个事件处理函数(onChange、handleSearch、onClearSearch)到子组件。

父组件

tsx 复制代码
import React, { useState } from 'react'
import SearchBar from './SearchBar'

const ParentComponent = () => {
  const [searchQuery, setSearchQuery] = useState('')
  // 处理搜索逻辑
  const handleSearch = () => {
    console.log('搜索:', searchQuery)
  }
  
  // 清空搜索框
  const onClearSearch = () => {
    setSearchQuery('')
  }
  
  return (
   <SearchBar
     value={searchQuery}
     onChange={({ target }) => setSearchQuery(target.value)}
     handleSearch={handleSearch}
     onClearSearch={onClearSearch}
     />
  )
}
export default ParentComponent

示例:子组件(SearchBar.tsx),样式用了tailwindcss v4

tsx 复制代码
import React from 'react'
import { FaMagnifyingGlass } from 'react-icons/fa6'
import { IoMdClose } from 'react-icons/io'

interface SearchBarProps {
  value: string
  onChange: (event: React.ChangeEvent<HTMLInputElement>) => void
  handleSearch: () => void
  onClearSearch: () => void
}

const SearchBar: React.FC<SearchBarProps> = ({
  value,
  onChange,
  handleSearch,
  onClearSearch,
}) => {
  return (
    <div className="w-80 flex items-center px-4 bg-slate-100 rounded-md">
      <input type="text" placeholder="搜索笔记"
          className="w-full text-xs bg-transparent py-[11px] outline-none"
          value={value}
          onChange={onChange} // 触发父组件的onChange方法
        />
       {value && (
          <IoMdClose 
            className="text-xl text-slate-500 cursor-pointer hover:text-black mr-3"
            onClick={onClearSearch} // 触发父组件的 handleSearch方法
            />
        )}
        <FaMagnifyingGlass
            className="text-slate-400 cursor-pointer hover:text-black"
            onClick={handleSearch} // 触发父组件的handleSearch方法
         />
     </div>
  )
}
export default SearchBar
事件传递过程分析
  1. 父组件定义方法
  • handleSearch(): 处理搜索逻辑
  • onClearSearch(): 清空搜索框
  • onChange(): 更新输入框内容
  1. 父组件通过props把这些方法传递给子组件
tsx 复制代码
<SearchBar
 value={searchQuery}
 onChange={({ target }) => setSearchQuery(target.value)}
 handleSearch={handleSearch}
 onClearSearch={onClearSearch}
/>
  1. 子组件SearchBar接受props并在事件触发时调用这些方法
  • 当输入框内容变化时,触发onChange(event), 更新searchQuery
  • 当点击放大镜图标时,调用handleSearch,执行搜索
  • 当点击关闭按钮时,调用onClearSearch,清空搜索框
  1. 为什么要这样做?
  • 父组件控制数据状态,子组件只是一个UI组件(受控组件)
  • 子组件无需管理数据,它只是接受value和事件处理函数
  • 代码更清晰,可复用性更高,不同地方的搜索框可以使用相同的SearchBar组件
  1. 总结
    ✅ 父组件定义事件方法,并通过 props 传递给子组件
    ✅ 子组件调用 props 里的方法 来通知父组件(例如 onChange、handleSearch、onClearSearch)
    ✅ 父组件负责管理状态,子组件只是一个展示组件
Vue3事件传递方式

在Vue3中,子组件不会调用父组件的方法,而是通过emit事件方式通知父组件,父组件在模板中监听该事件并执行回调。

父组件

vue 复制代码
<script setup>
import { ref } from 'vue'
import SearchBar from './SearchBar.vue'

const searchQuery = ref('')
// 监听子组件的事件
const handleSearch = () => {
  console.log('搜索:', searchQuery.value)
}

const onClearSearch = () => {
  searchQuery.value = ''
}
</script>

<template>
  <SearchBar
    v-model="searchQuery"
    @search="handleSearch"
    @clear="onClearSearch"
   />
</template>

子组件 SearchBar.vue

vue 复制代码
<script setup>
import { defineEmits, defineProps } from 'vue'

const props = defineProps({
  modelValue: String,
})

const emit = defineEmits(['update:modelValue', 'search', 'clear'])

const handleInput = (event) => {
  emit('update:modelValue', event.target.value) // 触发 v-model
}

const handleSearch = () => {
  emit('search') // 触发 search 事件
}

const handleClear = () => {
  emit('update:modelValue', '') // 触发 v-model 清空输入框
  emit('clear') // 触发 clear 事件
}
</script>

<template>
  <div class="search-bar">
    <input
      type="text"
      :value="modelValue"
      @input="handleInput"
      placeholder="搜索笔记"
    />
    <button v-if="modelValue" @click="handleClear">清空</button>
    <button @click="handleSearch">搜索</button>
  </div>
</template>

上面的子组件我们可以用3.4版本的defineModel简化下代码,

vue 复制代码
<script setup>
import { defineEmits } from 'vue'

const model = defineModel()
const emit = defineEmits(['search', 'clear'])
const handleSearch = () => {
  emit('search') // 触发 search 事件
}

const handleClear = () => {
  model.value = ''
  emit('clear') // 触发 clear 事件
}
</script>

<template>
  <div class="search-bar">
    <input
      type="text"
      v-model="model"
      placeholder="搜索笔记"
    />
    <button v-if="model" @click="handleClear">清空</button>
    <button @click="handleSearch">搜索</button>
  </div>
</template>
对比项 React (父传子) Vue 3 (emit 子传父)
事件触发方式 子组件调用父组件的 props 方法 子组件 emit 事件,父组件监听
状态管理方式 父组件控制状态,通过 props 传递 子组件通知父组件,父组件修改数据
v-model 实现 需要 useState + onChange defineProps + defineEmits
灵活性 父组件完全控制,代码可读性更高 子组件可独立触发事件,但需要 emit
总结
  1. React 是 "父组件控制子组件"

    • 逻辑和状态都在父组件

    • 子组件只调用 props 传递的方法,不需要管理状态

  2. Vue 3 是 "子组件通知父组件"

    • 子组件使用 emit 触发事件

    • 父组件监听事件并修改状态(比如 v-model)

两者设计理念不同,但都能够实现组件间的通信,React 更强调单向数据流 ,而 Vue 3 更灵活,支持 v-model 和 emit 来进行双向绑定。

相关推荐
Pedantic12 分钟前
SwiftUI 手势层级(Gesture Hierarchy)详解
前端
飘尘28 分钟前
前端转型全栈(Java后端)的快速上手指引
前端·后端·全栈
一颗烂土豆38 分钟前
Meshopt 压缩深度解析,为什么它比 Draco 更快
前端·javascript·webgl
YFF菲菲兔2 小时前
调度系统和调和系统的桥梁
react.js
浏览器工程师2 小时前
AI Agent 接浏览器任务,先别让它一路点到底
前端·后端
雨季mo浅忆2 小时前
VSCode自动格式化三要素
前端
爱勇宝2 小时前
深扒 Anthropic 1680 位工程师简历:应届生几乎没机会,AI 公司最缺的不是博士
前端·后端·程序员
kyriewen3 小时前
同事每天催我 Code Review,我写了个脚本让 AI 替我 review PR——现在他反过来催 AI 了
前端·javascript·ai编程
user20585561518135 小时前
Windows 项目安装时报 `node-sass` 错误,如何快速处理
前端