01-React基础入门——12-组件通信大全
组件通信大全一、组件通信概述1.1 通信场景分类通信类型场景常用方式父子通信父→子Props父子通信子→父回调函数兄弟通信同级组件状态提升跨层级通信祖先后代Context、Redux全局通信任意组件状态管理库二、父子组件通信2.1 父传子Props// 父组件 function Parent() { const [message, setMessage] useState(来自父组件的消息); return ( div Child message{message} / /div ); } // 子组件 function Child({ message }) { return div{message}/div; }2.2 子传父回调函数function Parent() { const [data, setData] useState(); const handleChildData (childData) { setData(childData); }; return ( div Child onSendData{handleChildData} / p子组件传来的数据: {data}/p /div ); } function Child({ onSendData }) { const sendData () { onSendData(这是子组件的数据); }; return button onClick{sendData}发送数据给父组件/button; }2.3 父组件调用子组件方法const Child forwardRef((props, ref) { const [value, setValue] useState(); useImperativeHandle(ref, () ({ reset: () setValue(), getValue: () value, focus: () inputRef.current.focus() })); return input value{value} onChange{(e) setValue(e.target.value)} /; }); function Parent() { const childRef useRef(null); return ( div Child ref{childRef} / button onClick{() childRef.current.reset()}重置/button /div ); }三、兄弟组件通信3.1 状态提升function Parent() { const [sharedState, setSharedState] useState(); return ( div SiblingA onUpdate{setSharedState} / SiblingB sharedState{sharedState} / /div ); } function SiblingA({ onUpdate }) { return button onClick{() onUpdate(来自兄弟A的消息)}发送消息/button; } function SiblingB({ sharedState }) { return div收到消息: {sharedState}/div; }3.2 通过父组件中转function Parent() { const [count, setCount] useState(0); const increment () setCount(count 1); const decrement () setCount(count - 1); return ( div CounterDisplay count{count} / CounterControls onIncrement{increment} onDecrement{decrement} / /div ); } function CounterDisplay({ count }) { return h1{count}/h1; } function CounterControls({ onIncrement, onDecrement }) { return ( div button onClick{onIncrement}/button button onClick{onDecrement}-/button /div ); }四、跨层级通信4.1 Context API 基础// 创建 Context const ThemeContext React.createContext(light); // 提供者 function ThemeProvider({ children }) { const [theme, setTheme] useState(light); const toggleTheme () { setTheme(prev prev light ? dark : light); }; return ( ThemeContext.Provider value{{ theme, toggleTheme }} {children} /ThemeContext.Provider ); } // 消费者函数组件 function ThemedButton() { const { theme, toggleTheme } useContext(ThemeContext); return ( button onClick{toggleTheme} style{{ background: theme dark ? #333 : #fff }} 当前主题: {theme} /button ); } // 使用 function App() { return ( ThemeProvider ThemedButton / /ThemeProvider ); }4.2 Context useReducerconst AppContext React.createContext(); const initialState { user: null, theme: light, notifications: [] }; function reducer(state, action) { switch (action.type) { case SET_USER: return { ...state, user: action.payload }; case TOGGLE_THEME: return { ...state, theme: state.theme light ? dark : light }; case ADD_NOTIFICATION: return { ...state, notifications: [...state.notifications, action.payload] }; default: return state; } } function AppProvider({ children }) { const [state, dispatch] useReducer(reducer, initialState); return ( AppContext.Provider value{{ state, dispatch }} {children} /AppContext.Provider ); } // 在任何组件中使用 function UserProfile() { const { state, dispatch } useContext(AppContext); const login () { dispatch({ type: SET_USER, payload: { name: 张三, id: 1 } }); }; return ( div {state.user ? div欢迎 {state.user.name}/div : button onClick{login}登录/button} /div ); }4.3 嵌套 Contextconst UserContext React.createContext(); const ThemeContext React.createContext(); const LanguageContext React.createContext(); function App() { return ( UserContext.Provider value{{ user: 张三 }} ThemeContext.Provider value{{ theme: dark }} LanguageContext.Provider value{{ lang: zh-CN }} Dashboard / /LanguageContext.Provider /ThemeContext.Provider /UserContext.Provider ); } function Dashboard() { const user useContext(UserContext); const theme useContext(ThemeContext); const language useContext(LanguageContext); return div{user.user} - {theme.theme} - {language.lang}/div; }五、使用状态管理库5.1 Zustand 示例npminstallzustandimport create from zustand; const useStore create((set) ({ count: 0, user: null, increment: () set((state) ({ count: state.count 1 })), decrement: () set((state) ({ count: state.count - 1 })), setUser: (user) set({ user }) })); // 组件 A function Counter() { const { count, increment, decrement } useStore(); return ( div button onClick{decrement}-/button span{count}/span button onClick{increment}/button /div ); } // 组件 B自动响应状态变化 function Display() { const count useStore((state) state.count); return div当前计数: {count}/div; }5.2 Redux Toolkit 示例npminstallreduxjs/toolkit react-reduximport { configureStore, createSlice } from reduxjs/toolkit; import { Provider, useSelector, useDispatch } from react-redux; const counterSlice createSlice({ name: counter, initialState: { value: 0 }, reducers: { increment: (state) { state.value 1; }, decrement: (state) { state.value - 1; } } }); const store configureStore({ reducer: counterSlice.reducer }); function Counter() { const count useSelector((state) state.value); const dispatch useDispatch(); return ( div button onClick{() dispatch(counterSlice.actions.decrement())}-/button span{count}/span button onClick{() dispatch(counterSlice.actions.increment())}/button /div ); } function App() { return ( Provider store{store} Counter / /Provider ); }六、事件总线不推荐// 简单的事件总线实现用于理解概念 class EventBus { constructor() { this.events {}; } on(event, callback) { if (!this.events[event]) this.events[event] []; this.events[event].push(callback); } emit(event, data) { if (this.events[event]) { this.events[event].forEach(callback callback(data)); } } off(event, callback) { if (this.events[event]) { this.events[event] this.events[event].filter(cb cb ! callback); } } } const eventBus new EventBus(); // 组件 A function Sender() { const sendMessage () { eventBus.emit(message, 来自发送者的消息); }; return button onClick{sendMessage}发送/button; } // 组件 B function Receiver() { const [message, setMessage] useState(); useEffect(() { const handler (msg) setMessage(msg); eventBus.on(message, handler); return () eventBus.off(message, handler); }, []); return div收到: {message}/div; }七、通信模式对比模式优点缺点适用场景Props简单、明确逐层传递繁琐浅层组件树Context跨层级传递过度使用影响性能主题、语言、用户信息Zustand轻量、简单生态相对小中小型应用Redux成熟、生态丰富样板代码多大型复杂应用事件总线灵活难以追踪、维护困难不推荐使用八、最佳实践8.1 选择合适的通信方式// 简单场景Props function Simple() { return Child name张三 /; } // 深层传递Context const UserContext createContext(); // 复杂状态Zustand/Redux const useStore create(...);8.2 避免 Props Drilling// ❌ 不好的做法层层传递 GrandParent user{user} Parent user{user} Child user{user} GrandChild user{user} / /Child /Parent /GrandParent // ✅ 好的做法使用 Context const UserContext createContext(); UserContext.Provider value{user} GrandParent Parent Child GrandChild / /Child /Parent /GrandParent /UserContext.Provider8.3 组件设计原则// 容器组件负责逻辑 function UserContainer() { const [user, setUser] useState(null); const [loading, setLoading] useState(true); useEffect(() { fetchUser().then(data { setUser(data); setLoading(false); }); }, []); return UserProfile user{user} loading{loading} /; } // 展示组件负责 UI function UserProfile({ user, loading }) { if (loading) return div加载中.../div; return div{user.name}/div; }九、常见问题9.1 Context 性能优化// 拆分 Context 避免不必要的重渲染 const UserContext createContext(); const ThemeContext createContext(); // 使用 useMemo 优化 Provider 值 function AppProvider({ children }) { const [user, setUser] useState(null); const userValue useMemo(() ({ user, setUser }), [user]); return ( UserContext.Provider value{userValue} {children} /UserContext.Provider ); }9.2 循环依赖// 避免组件之间相互导入导致的循环依赖 // 解决方案提取共享逻辑到单独文件 // shared/types.js export const SHARED_CONSTANTS {}; // 或使用 Context 解耦十、练习题基础题实现一个简单的计数器使用兄弟组件通信一个组件显示一个组件控制实现一个主题切换功能使用 Context进阶题实现一个购物车使用 Zustand 管理状态实现一个通知系统任意组件可以发送通知参考答案// 购物车示例Zustand const useCartStore create((set) ({ items: [], addItem: (item) set((state) ({ items: [...state.items, item] })), removeItem: (id) set((state) ({ items: state.items.filter(item item.id ! id) })), clearCart: () set({ items: [] }), total: () { const state useCartStore.getState(); return state.items.reduce((sum, item) sum item.price * item.quantity, 0); } })); function ProductList() { const addItem useCartStore(state state.addItem); return ( button onClick{() addItem({ id: 1, name: 商品, price: 100, quantity: 1 })} 添加到购物车 /button ); } function Cart() { const items useCartStore(state state.items); const removeItem useCartStore(state state.removeItem); const total useCartStore(state state.total()); return ( div {items.map(item ( div key{item.id} {item.name} - ¥{item.price} button onClick{() removeItem(item.id)}删除/button /div ))} div总计: ¥{total}/div /div ); }十一、小结通信类型推荐方案备注父子Props / 回调最常用兄弟状态提升简单场景跨层级Context避免过度使用全局Zustand / Redux大型应用任意组件状态管理库推荐 Zustand核心要点优先使用 Props 进行父子通信状态提升解决兄弟通信Context 解决跨层级传递复杂状态使用状态管理库避免 Props Drilling