React
在 React 中,数据传递是构建组件化应用的核心概念之一。React 提供了多种方式来实现父子组件、兄弟组件以及跨层级组件之间的数据传递和通信。以下是 React 中传递数据的所有主要用法:
1. 通过 props 传递数据
这是最常见的方式,用于父组件向子组件传递数据。
示例代码
父组件 (ParentComponent.js)
import React from 'react';
import ChildComponent from './ChildComponent';
const ParentComponent = () => {
const message = "Hello from Parent!";
return <ChildComponent message={message} />;
};
export default ParentComponent;
子组件 (ChildComponent.js)
import React from 'react';
const ChildComponent = ({ message }) => {
return <p>{message}</p>;
};
export default ChildComponent;
2. 使用回调函数(Callback Props)
父组件可以通过 props 向子组件传递回调函数,子组件可以在需要时调用这些函数以通知父组件某些事件的发生。
示例代码
父组件 (ParentComponent.js)
import React, { useState } from 'react';
import ChildComponent from './ChildComponent';
const ParentComponent = () => {
const [data, setData] = useState('');
const handleDataChange = (newData) => {
setData(newData);
};
return (
<>
<ChildComponent onDataChange={handleDataChange} />
<p>Data received from child: {data}</p>
</>
);
};
export default ParentComponent;
子组件 (ChildComponent.js)
import React from 'react';
const ChildComponent = ({ onDataChange }) => {
const handleClick = () => {
onDataChange('New Data from Child');
};
return <button onClick={handleClick}>Send Data to Parent</button>;
};
export default ChildComponent;
3. 通过 Context API 传递数据
Context API 允许你在不使用 props 的情况下传递数据,特别适用于深度嵌套的组件树中共享状态。
示例代码
创建 Context
import React, { createContext, useContext } from 'react';
const MyContext = createContext();
// 使用 Provider 组件提供数据
const ParentComponent = () => {
const value = "Shared data";
return (
<MyContext.Provider value={value}>
<ChildComponent />
</MyContext.Provider>
);
};
消费 Context
import React, { useContext } from 'react';
const ChildComponent = () => {
const value = useContext(MyContext);
return <p>{value}</p>;
};
4. 使用 useReducer 和 Context 管理复杂状态
对于更复杂的状态管理需求,可以结合 useReducer 和 Context 来创建全局状态管理器。
5. 使用 forwardRef 和 useImperativeHandle
当需要直接操作子组件的 DOM 或方法时,可以使用 forwardRef 和 useImperativeHandle。
示例代码
子组件 (ChildComponent.js)
import React, { useRef, useImperativeHandle, forwardRef } from 'react';
const ChildComponent = forwardRef((props, ref) => {
const inputRef = useRef(null);
useImperativeHandle(ref, () => ({
focusInput: () => {
inputRef.current.focus();
}
}));
return <input ref={inputRef} type="text" />;
});
export default ChildComponent;
父组件 (ParentComponent.js)
import React, { useRef } from 'react';
import ChildComponent from './ChildComponent';
const ParentComponent = () => {
const childComponentRef = useRef(null);
const handleFocus = () => {
childComponentRef.current.focusInput();
};
return (
<>
<ChildComponent ref={childComponentRef} />
<button onClick={handleFocus}>Focus Input</button>
</>
);
};
export default ParentComponent;
6. 使用第三方状态管理库
对于大型应用程序或需要更复杂的全局状态管理的情况,可以考虑使用 Redux、MobX 或其他状态管理库。
7. 通过 props.children 传递内容
props.children 是一种特殊类型的 prop,允许父组件向子组件传递任意内容。
示例代码
父组件 (ParentComponent.js)
import React from 'react';
import ChildComponent from './ChildComponent';
const ParentComponent = () => {
return (
<ChildComponent>
<p>This content is passed as props.children.</p>
</ChildComponent>
);
};
export default ParentComponent;
子组件 (ChildComponent.js)
import React from 'react';
const ChildComponent = ({ children }) => {
return (
<div style={{ border: '1px solid black', padding: '10px' }}>
<h2>Child Component</h2>
{children}
</div>
);
};
export default ChildComponent;
8. 使用事件冒泡
虽然不是直接的数据传递方式,但事件冒泡机制可以让子组件触发的事件冒泡到父组件,从而实现通信。
总结
props: 最基础的数据传递方式,从父组件到子组件。- 回调函数(Callback Props): 父组件接收来自子组件的通知或数据。
Context API: 跨多层组件传递数据,避免props钻透。useReducer和Context: 复杂状态管理。forwardRef和useImperativeHandle: 直接访问子组件的方法或 DOM。- 第三方状态管理库: 对于大型应用或复杂状态管理。
props.children: 传递内容给子组件。- 事件冒泡: 子组件通过事件与父组件通信。
选择哪种方式取决于你的具体需求和应用程序的复杂度。通常来说,尽量优先使用 props 和事件来进行父子组件之间的通信,只有在确实需要时才考虑使用 ref 或上下文等高级特性。
Vue
在 Vue 3 中,组件之间的通信机制得到了进一步的优化和简化。Vue 3 引入了 Composition API 和更好的 TypeScript 支持,使得代码更加模块化和易于维护。以下是使用 Vue 3 方式进行组件通信的详细示例。
1. 通过 props 传递数据
这是最常见的方式,用于父组件向子组件传递数据。
示例代码
父组件 (ParentComponent.vue)
<template>
<div>
<h1>Parent Component</h1>
<ChildComponent :message="parentMessage" />
</div>
</template>
<script setup>
import { ref } from 'vue';
import ChildComponent from './ChildComponent.vue';
const parentMessage = ref('Hello from Parent!');
</script>
子组件 (ChildComponent.vue)
<template>
<p>{{ message }}</p>
</template>
<script setup>
defineProps({
message: String
});
</script>
2. 通过 $emit 触发事件
子组件可以通过 emit 方法触发自定义事件,将数据发送给父组件。
示例代码
父组件 (ParentComponent.vue)
<template>
<div>
<h1>Parent Component</h1>
<ChildComponent @child-event="handleChildEvent" />
<p>Data received from child: {{ childData }}</p>
</div>
</template>
<script setup>
import { ref } from 'vue';
import ChildComponent from './ChildComponent.vue';
const childData = ref('');
const handleChildEvent = (data) => {
childData.value = data;
};
</script>
子组件 (ChildComponent.vue)
<template>
<button @click="sendDataToParent">Send Data to Parent</button>
</template>
<script setup>
import { defineEmits } from 'vue';
const emit = defineEmits(['child-event']);
const sendDataToParent = () => {
emit('child-event', 'New Data from Child');
};
</script>
3. 使用 Provide / Inject
provide 和 inject 是一种在多层级组件间共享状态的方法,适用于需要跨多层传递数据的场景。
示例代码
父组件 (ParentComponent.vue)
<template>
<div>
<h1>Parent Component</h1>
<GrandChildComponent />
</div>
</template>
<script setup>
import { provide, ref } from 'vue';
import GrandChildComponent from './GrandChildComponent.vue';
const sharedState = ref('Shared Data');
provide('sharedState', sharedState);
</script>
孙子组件 (GrandChildComponent.vue)
<template>
<p>{{ injectedState }}</p>
</template>
<script setup>
import { inject } from 'vue';
const injectedState = inject('sharedState');
</script>
4. 使用全局事件总线(Event Bus)
虽然 Vue 3 推荐使用 Composition API 和其他更现代的方式来处理组件通信,但在某些情况下,你仍然可以使用全局事件总线来实现组件间的通信。
创建事件总线
// eventBus.js
import { createApp } from 'vue';
const app = createApp({});
export const eventBus = app.config.globalProperties.$bus = new Vue();
使用事件总线
发布事件
<template>
<button @click="publishEvent">Publish Event</button>
</template>
<script setup>
import { eventBus } from './eventBus';
const publishEvent = () => {
eventBus.$emit('custom-event', 'Event Data');
};
</script>
订阅事件
<template>
<p>{{ eventData }}</p>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue';
import { eventBus } from './eventBus';
const eventData = ref(null);
onMounted(() => {
eventBus.$on('custom-event', (data) => {
eventData.value = data;
});
});
onUnmounted(() => {
eventBus.$off('custom-event');
});
</script>
5. 使用 Vuex 或 Pinia 状态管理库
对于大型应用或需要复杂状态管理的情况,推荐使用专门的状态管理库如 Vuex 或 Pinia。
使用 Pinia
-
安装 Pinia
npm install pinia -
创建 Store
// store/index.js import { defineStore } from 'pinia'; export const useMainStore = defineStore('main', { state: () => ({ count: 0, }), actions: { increment() { this.count++; } } }); -
使用 Store
主文件 (
main.js)import { createApp } from 'vue'; import { createPinia } from 'pinia'; import App from './App.vue'; const app = createApp(App); app.use(createPinia()); app.mount('#app');组件中使用
<template> <div> <p>Count: {{ count }}</p> <button @click="increment">Increment</button> </div> </template> <script setup> import { useMainStore } from './store'; const mainStore = useMainStore(); const { count } = storeToRefs(mainStore); const increment = () => { mainStore.increment(); }; </script>
总结
props和$emit: 最基础的数据传递方式,从父组件到子组件以及从子组件到父组件。provide和inject: 跨多层组件传递数据。- 全局事件总线: 实现松耦合的组件通信,但尽量避免过度使用。
- 状态管理库 (Vuex/Pinia): 对于大型应用或复杂状态管理需求。
选择哪种方式取决于你的具体需求和应用程序的复杂度。通常来说,尽量优先使用 props 和 $emit 进行父子组件之间的通信,只有在确实需要时才考虑使用 provide/inject 或状态管理库等高级特性。
- storeToRefs,你可以保持解构后的状态和 getter 的响应性

5358

被折叠的 条评论
为什么被折叠?



