React 组件通信方式
Props、Context、Redux、Ref 四种组件通信方式的使用场景和实现
问题
React 中组件之间如何通信?常见的通信方式有哪些?
解答
1. Props - 父子组件通信
最基础的通信方式,父组件通过 props 向子组件传递数据和回调函数。
// 父组件
function Parent() {
const [count, setCount] = useState(0);
// 通过 props 传递数据和回调
return (
<Child
count={count}
onIncrement={() => setCount(count + 1)}
/>
);
}
// 子组件
function Child({ count, onIncrement }) {
return (
<div>
<p>Count: {count}</p>
<button onClick={onIncrement}>+1</button>
</div>
);
}
2. Context - 跨层级通信
避免 props 逐层传递,适合主题、用户信息等全局数据。
// 创建 Context
const ThemeContext = createContext('light');
// 顶层提供数据
function App() {
const [theme, setTheme] = useState('light');
return (
<ThemeContext.Provider value={{ theme, setTheme }}>
<Page />
</ThemeContext.Provider>
);
}
// 中间层不需要传递 props
function Page() {
return <Button />;
}
// 任意深层组件直接消费
function Button() {
const { theme, setTheme } = useContext(ThemeContext);
return (
<button
style={{ background: theme === 'dark' ? '#333' : '#fff' }}
onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}
>
切换主题
</button>
);
}
3. Redux - 全局状态管理
适合复杂应用的状态管理,单向数据流,可预测。
// store.js - 创建 store
import { configureStore, createSlice } from '@reduxjs/toolkit';
const counterSlice = createSlice({
name: 'counter',
initialState: { value: 0 },
reducers: {
increment: (state) => { state.value += 1; },
decrement: (state) => { state.value -= 1; },
},
});
export const { increment, decrement } = counterSlice.actions;
export const store = configureStore({ reducer: { counter: counterSlice.reducer } });
// App.jsx - 提供 store
import { Provider } from 'react-redux';
import { store } from './store';
function App() {
return (
<Provider store={store}>
<Counter />
</Provider>
);
}
// Counter.jsx - 使用 store
import { useSelector, useDispatch } from 'react-redux';
import { increment, decrement } from './store';
function Counter() {
// 读取状态
const count = useSelector((state) => state.counter.value);
// 派发 action
const dispatch = useDispatch();
return (
<div>
<span>{count}</span>
<button onClick={() => dispatch(increment())}>+</button>
<button onClick={() => dispatch(decrement())}>-</button>
</div>
);
}
4. Ref - 直接访问组件实例或 DOM
父组件直接调用子组件的方法,需配合 forwardRef 和 useImperativeHandle。
import { useRef, forwardRef, useImperativeHandle } from 'react';
// 子组件暴露方法给父组件
const Input = forwardRef((props, ref) => {
const inputRef = useRef();
// 定义暴露给父组件的方法
useImperativeHandle(ref, () => ({
focus: () => inputRef.current.focus(),
clear: () => { inputRef.current.value = ''; },
}));
return <input ref={inputRef} {...props} />;
});
// 父组件调用子组件方法
function Form() {
const inputRef = useRef();
return (
<div>
<Input ref={inputRef} placeholder="输入内容" />
<button onClick={() => inputRef.current.focus()}>聚焦</button>
<button onClick={() => inputRef.current.clear()}>清空</button>
</div>
);
}
通信方式对比
| 方式 | 适用场景 | 复杂度 |
|---|---|---|
| Props | 父子组件、层级浅 | 低 |
| Context | 跨多层、全局配置 | 中 |
| Redux | 大型应用、复杂状态 | 高 |
| Ref | 命令式操作、访问 DOM | 中 |
关键点
- Props 是单向数据流的基础,子传父通过回调函数
- Context 解决 props drilling,但频繁更新会导致性能问题
- Redux 遵循单一数据源、状态只读、纯函数修改三原则
- Ref 打破了声明式编程,应谨慎使用
- 优先使用 Props,按需引入其他方案,避免过度设计
目录