我为您整理一份更加全面的所有给 children 传值的方式完整指南。
📚 所有给 Children 传值的方式(完全指南)
1️⃣ Context API(上下文API)
使用场景:全局状态共享、避免prop drilling、跨级组件通信
typescript
/**
* 场景:需要跨越多个中间组件传递数据
* 示例:主题、语言、用户信息等全局配置
*/
import React, { createContext, useContext, ReactNode, useState } from 'react';
// 创建Context
interface ThemeContextType {
theme: 'light' | 'dark';
toggleTheme: () => void;
}
const ThemeContext = createContext<ThemeContextType>({
theme: 'light',
toggleTheme: () => {},
});
// Provider组件
interface ThemeProviderProps {
children: ReactNode;
}
export const ThemeProvider: React.FC<ThemeProviderProps> = ({ children }) => {
const [theme, setTheme] = useState<'light' | 'dark'>('light');
const toggleTheme = () => {
setTheme(prev => prev === 'light' ? 'dark' : 'light');
};
// 通过Context.Provider向所有后代组件传值
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
};
// 使用 useContext Hook 访问Context中的值
const Button: React.FC = () => {
const { theme, toggleTheme } = useContext(ThemeContext);
return (
<button
onClick={toggleTheme}
style={{ background: theme === 'light' ? '#fff' : '#000' }}
>
当前主题: {theme}
</button>
);
};
// 使用示例
// <ThemeProvider>
// <Button />
// <OtherComponents /> {/* 任何深层组件都能访问Context */}
// </ThemeProvider>
2️⃣ React.Children.map + React.cloneElement
使用场景:统一修改所有子组件的props、类型过滤、条件渲染
typescript
/**
* 场景:ButtonGroup 需要统一给所有Button子组件设置大小和颜色
*/
import React, { ReactNode } from 'react';
interface ButtonGroupProps {
children: ReactNode;
size?: 'small' | 'medium' | 'large';
color?: 'primary' | 'secondary' | 'danger';
disabled?: boolean;
}
const ButtonGroup: React.FC<ButtonGroupProps> = ({
children,
size = 'medium',
color = 'primary',
disabled = false
}) => {
// 使用React.Children.map遍历所有子组件
const enhancedChildren = React.Children.map(children, (child) => {
// 检查是否为有效的React元素
if (!React.isValidElement(child)) {
return child;
}
// 可选:过滤只处理特定类型的子组件
// if (child.type.name !== 'Button') {
// return child;
// }
// 使用React.cloneElement克隆并合并新props
return React.cloneElement(child, {
size, // 注入统一的size
color, // 注入统一的color
disabled, // 注入统一的disabled状态
// 保留原有props(新props优先级更高)
});
});
return <div className="button-group">{enhancedChildren}</div>;
};
// 使用示例
// <ButtonGroup size="large" color="primary" disabled={false}>
// <Button>确定</Button>
// <Button>取消</Button>
// <Button>删除</Button>
// </ButtonGroup>
3️⃣ Render Props(函数作为 children)
使用场景:需要children访问父组件的状态/方法、灵活的渲染控制
typescript
/**
* 场景:List组件让使用者控制每项如何渲染
*/
import React, { ReactNode } from 'react';
interface ListProps<T> {
// children是一个函数,接收item和index,返回ReactNode
children: (item: T, index: number, isEven: boolean) => ReactNode;
data: T[];
}
function List<T>({ data, children }: ListProps<T>) {
return (
<ul>
{data.map((item, index) => (
<li key={index}>
{/* 调用children函数并传入数据 */}
{children(item, index, index % 2 === 0)}
</li>
))}
</ul>
);
}
// 使用示例
const users = [
{ id: 1, name: 'Alice', role: 'admin' },
{ id: 2, name: 'Bob', role: 'user' },
{ id: 3, name: 'Charlie', role: 'user' },
];
// <List data={users}>
// {(user, index, isEven) => (
// <div style={{ background: isEven ? '#f0f0f0' : '#fff' }}>
// <span>{index + 1}. {user.name}</span>
// <span>角色: {user.role}</span>
// </div>
// )}
// </List>
4️⃣ Render Props + 状态管理
使用场景:children需要访问父组件的复杂状态和多个方法
typescript
/**
* 场景:Form组件提供表单状态和验证方法给children
*/
import React, { ReactNode, useState, useCallback } from 'react';
interface FormValue {
[key: string]: any;
}
interface FormRenderPropsArgs {
values: FormValue;
setValues: (values: FormValue) => void;
setFieldValue: (field: string, value: any) => void;
errors: { [key: string]: string };
setFieldError: (field: string, error: string) => void;
submit: () => void;
}
interface FormProps {
children: (args: FormRenderPropsArgs) => ReactNode;
onSubmit?: (values: FormValue) => void;
initialValues?: FormValue;
}
const Form: React.FC<FormProps> = ({
children,
onSubmit,
initialValues = {}
}) => {
const [values, setValues] = useState<FormValue>(initialValues);
const [errors, setErrors] = useState<{ [key: string]: string }>({});
// 提供设置单个字段值的方法
const setFieldValue = useCallback((field: string, value: any) => {
setValues(prev => ({ ...prev, [field]: value }));
}, []);
// 提供设置单个字段错误的方法
const setFieldError = useCallback((field: string, error: string) => {
setErrors(prev => ({ ...prev, [field]: error }));
}, []);
// 提供提交方法
const submit = useCallback(() => {
onSubmit?.(values);
}, [values, onSubmit]);
// 将所有状态和方法通过Render Props传给children
return (
<form onSubmit={(e) => { e.preventDefault(); submit(); }}>
{children({
values,
setValues,
setFieldValue,
errors,
setFieldError,
submit
})}
</form>
);
};
// 使用示例
// <Form initialValues={{ email: '', password: '' }}>
// {({ values, setFieldValue, errors, submit }) => (
// <>
// <input
// value={values.email}
// onChange={(e) => setFieldValue('email', e.target.value)}
// />
// <input
// type="password"
// value={values.password}
// onChange={(e) => setFieldValue('password', e.target.value)}
// />
// <button onClick={submit}>提交</button>
// </>
// )}
// </Form>
5️⃣ forwardRef + useImperativeHandle
使用场景:父组件需要调用children组件的命令式方法
typescript
/**
* 场景:Modal组件暴露open/close方法给使用者
*/
import React, {
forwardRef,
useImperativeHandle,
useRef,
ReactNode,
useState
} from 'react';
interface ModalHandle {
open: () => void;
close: () => void;
toggle: () => void;
}
interface ModalProps {
children: ReactNode;
title?: string;
}
const Modal = forwardRef<ModalHandle, ModalProps>(
({ children, title }, ref) => {
const [isOpen, setIsOpen] = useState(false);
// 使用useImperativeHandle暴露方法给ref
useImperativeHandle(ref, () => ({
open: () => setIsOpen(true),
close: () => setIsOpen(false),
toggle: () => setIsOpen(prev => !prev)
}));
if (!isOpen) return null;
return (
<div className="modal">
<div className="modal-header">
<h2>{title}</h2>
</div>
<div className="modal-body">
{children}
</div>
<div className="modal-footer">
<button onClick={() => setIsOpen(false)}>关闭</button>
</div>
</div>
);
}
);
Modal.displayName = 'Modal';
// 使用示例
const ModalExample: React.FC = () => {
const modalRef = useRef<ModalHandle>(null);
return (
<>
<button onClick={() => modalRef.current?.open()}>打开弹窗</button>
<Modal ref={modalRef} title="我的弹窗">
<p>这是弹窗内容</p>
</Modal>
</>
);
};
6️⃣ 高阶组件(HOC)
使用场景:为多个组件添加统一的增强功能、功能复用
typescript
/**
* 场景:为所有子组件添加loading状态
*/
import React, { ComponentType, ReactNode, useState } from 'react';
interface WithLoadingProps {
isLoading?: boolean;
loadingText?: string;
}
// HOC工厂函数
function withLoading<P extends object>(
WrappedComponent: ComponentType<P>
): React.FC<P & WithLoadingProps> {
return ({ isLoading = false, loadingText = '加载中...', ...props }) => {
if (isLoading) {
return <div className="loading">{loadingText}</div>;
}
return <WrappedComponent {...(props as P)} />;
};
}
// 或者用HOC增强children
interface EnhancedContainerProps {
children: ReactNode;
isLoading?: boolean;
loadingComponent?: ReactNode;
}
const EnhancedContainer: React.FC<EnhancedContainerProps> = ({
children,
isLoading = false,
loadingComponent = <div>加载中...</div>
}) => {
// 在children外面包裹loading状态
if (isLoading) {
return <>{loadingComponent}</>;
}
// 使用map和cloneElement给children注入props
const enhancedChildren = React.Children.map(children, (child) => {
if (!React.isValidElement(child)) return child;
return React.cloneElement(child, {
'data-loading': isLoading,
...child.props
});
});
return <>{enhancedChildren}</>;
};
// 使用示例
// <EnhancedContainer isLoading={false}>
// <UserList />
// <UserProfile />
// </EnhancedContainer>
7️⃣ 复合组件模式(Compound Components)
使用场景:组件间有强关联,需要相互通信(如Select/Option、Menu/Item)
typescript
/**
* 场景:Tabs组件及其子组件TabPane的协作
*/
import React, { createContext, useContext, ReactNode, useState } from 'react';
// 创建Context用于组件间通信
interface TabsContextType {
activeKey: string;
onTabChange: (key: string) => void;
}
const TabsContext = createContext<TabsContextType>({
activeKey: '',
onTabChange: () => {},
});
// 主组件:Tabs
interface TabsProps {
children: React.ReactElement<TabPaneProps>[];
defaultActiveKey?: string;
}
const Tabs: React.FC<TabsProps> = ({ children, defaultActiveKey = '' }) => {
const [activeKey, setActiveKey] = useState(defaultActiveKey);
// 通过Context向子组件传递状态和方法
return (
<TabsContext.Provider value={{ activeKey, onTabChange: setActiveKey }}>
<div className="tabs">
{/* 标签栏 */}
<div className="tabs-nav">
{children.map((pane) => (
<button
key={pane.key}
className={activeKey === pane.key ? 'active' : ''}
onClick={() => setActiveKey(pane.key as string)}
>
{pane.props.label}
</button>
))}
</div>
{/* 内容区 */}
<div className="tabs-content">
{children}
</div>
</div>
</TabsContext.Provider>
);
};
// 子组件:TabPane
interface TabPaneProps {
key?: string;
label: string;
children: ReactNode;
}
const TabPane: React.FC<TabPaneProps> = ({ children }) => {
const { activeKey } = useContext(TabsContext);
// 子组件从Context获取数据,判断是否应该显示
// 注意:这里的key应该通过props.key访问
if (activeKey !== (children as any)?.key) {
return null;
}
return <div className="tab-pane">{children}</div>;
};
// 优化版本:让TabPane正确获取key
const TabPaneContent: React.FC<TabPaneProps & { activeKey: string }> = ({
children,
activeKey,
label
}) => {
return (
<div className="tab-pane" style={{ display: activeKey === label ? 'block' : 'none' }}>
{children}
</div>
);
};
// 使用示例
// <Tabs defaultActiveKey="tab1">
// <TabPane key="tab1" label="标签1">内容1</TabPane>
// <TabPane key="tab2" label="标签2">内容2</TabPane>
// </Tabs>
8️⃣ useContext Hook(直接使用Context)
使用场景:子组件需要直接访问父组件通过Context提供的值
typescript
/**
* 场景:表单组件库中,FormItem需要访问Form的状态
*/
import React, { createContext, useContext, ReactNode, useState } from 'react';
// FormContext
interface FormContextType {
formData: { [key: string]: any };
updateField: (name: string, value: any) => void;
errors: { [key: string]: string };
}
const FormContext = createContext<FormContextType | null>(null);
// Form组件 - 提供Context
interface FormProps {
children: ReactNode;
onSubmit?: (data: any) => void;
}
const Form: React.FC<FormProps> = ({ children, onSubmit }) => {
const [formData, setFormData] = useState<{ [key: string]: any }>({});
const [errors, setErrors] = useState<{ [key: string]: string }>({});
const updateField = (name: string, value: any) => {
setFormData(prev => ({ ...prev, [name]: value }));
};
return (
<FormContext.Provider value={{ formData, updateField, errors }}>
<form onSubmit={(e) => {
e.preventDefault();
onSubmit?.(formData);
}}>
{children}
</form>
</FormContext.Provider>
);
};
// FormItem组件 - 使用Context
interface FormItemProps {
name: string;
label: string;
children: ReactNode;
}
const FormItem: React.FC<FormItemProps> = ({ name, label, children }) => {
const context = useContext(FormContext);
if (!context) {
throw new Error('FormItem必须在Form组件内使用');
}
const { formData, updateField } = context;
return (
<div className="form-item">
<label>{label}</label>
{React.isValidElement(children) &&
React.cloneElement(children, {
value: formData[name] || '',
onChange: (e: React.ChangeEvent<HTMLInputElement>) => {
updateField(name, e.target.value);
}
} as any)}
</div>
);
};
// Input组件
const Input: React.FC<{ value?: string; onChange?: (e: any) => void }> = (props) => (
<input {...props} />
);
// 使用示例
// <Form>
// <FormItem name="username" label="用户名">
// <Input />
// </FormItem>
// <FormItem name="email" label="邮箱">
// <Input />
// </FormItem>
// </Form>
9️⃣ Consumer + Provider 组合
使用场景:需要同时获取多个Context或在类组件中使用Context
typescript
/**
* 场景:类组件中使用Context(旧API)
*/
import React, { createContext } from 'react';
interface User {
id: number;
name: string;
}
const UserContext = createContext<User | null>(null);
// 使用Consumer访问Context
class UserProfile extends React.Component {
render() {
return (
<UserContext.Consumer>
{(user) => (
<div>
{user ? (
<>
<h1>{user.name}</h1>
<p>ID: {user.id}</p>
</>
) : (
<p>未登录</p>
)}
</div>
)}
</UserContext.Consumer>
);
}
}
// 或在函数组件中使用多个Consumer
const MultiContextExample: React.FC = () => {
return (
<UserContext.Consumer>
{(user) => (
<div>
<p>用户信息: {user?.name}</p>
{/* 可以嵌套多个Consumer */}
</div>
)}
</UserContext.Consumer>
);
};
// 使用示例
// <UserContext.Provider value={{ id: 1, name: 'Alice' }}>
// <UserProfile />
// </UserContext.Provider>
🔟 自定义 Hook 共享逻辑
使用场景:多个组件需要共享相同的逻辑和状态
typescript
/**
* 场景:多个表单字段需要共享验证逻辑
*/
import React, { useState, useCallback, ReactNode } from 'react';
// 自定义Hook - 用于共享表单字段逻辑
interface UseFieldProps {
initialValue?: string;
validate?: (value: string) => string;
}
function useField({ initialValue = '', validate }: UseFieldProps = {}) {
const [value, setValue] = useState(initialValue);
const [error, setError] = useState('');
const handleChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
const newValue = e.target.value;
setValue(newValue);
// 实时验证
if (validate) {
setError(validate(newValue));
}
}, [validate]);
return { value, setValue, error, setError, handleChange };
}
// 父组件使用自定义Hook
interface FormExampleProps {
children: ReactNode;
}
const FormExample: React.FC<FormExampleProps> = ({ children }) => {
const emailField = useField({
validate: (value) => {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value) ? '' : '邮箱格式不正确';
}
});
const passwordField = useField({
validate: (value) => {
return value.length >= 6 ? '' : '密码至少6位';
}
});
// 通过render props传递hooks的返回值
return (
<div>
{typeof children === 'function' ? (
(children as Function)({ emailField, passwordField })
) : (
children
)}
</div>
);
};
// 使用示例
// <FormExample>
// {({ emailField, passwordField }) => (
// <>
// <input {...emailField} placeholder="邮箱" />
// {emailField.error && <p>{emailField.error}</p>}
// <input {...passwordField} type="password" placeholder="密码" />
// {passwordField.error && <p>{passwordField.error}</p>}
// </>
// )}
// </FormExample>
1️⃣1️⃣ 直接修改 React.Children 数组
使用场景:需要对children进行复杂的数组操作
typescript
/**
* 场景:Carousel组件需要处理children的循环滚动
*/
import React, { ReactNode } from 'react';
interface CarouselProps {
children: ReactNode;
autoplay?: boolean;
speed?: number;
}
const Carousel: React.FC<CarouselProps> = ({
children,
autoplay = true,
speed = 3000
}) => {
// 将children转换为数组便于处理
const childArray = React.Children.toArray(children).filter(
(child) => React.isValidElement(child)
);
// 可以进行数组操作
const reversed = [...childArray].reverse(); // 反向排列
const filtered = childArray.filter((_, i) => i % 2 === 0); // 过滤偶数项
const duplicated = [...childArray, ...childArray]; // 复制
return (
<div className="carousel">
{childArray.map((child, index) => (
<div key={index} className="carousel-item">
{child}
</div>
))}
</div>
);
};
// 使用示例
// <Carousel autoplay speed={5000}>
// <Slide>Slide 1</Slide>
// <Slide>Slide 2</Slide>
// <Slide>Slide 3</Slide>
// </Carousel>
1️⃣2️⃣ 通过 Props Drilling(逐级传递)
使用场景:层级不深、只需传递简单数据
typescript
/**
* 场景:简单的props逐级传递
*/
import React, { ReactNode } from 'react';
interface LevelAProps {
children: ReactNode;
userRole: 'admin' | 'user';
}
const LevelA: React.FC<LevelAProps> = ({ children, userRole }) => {
// 逐级传递userRole给子组件
return (
<div className="level-a">
{React.Children.map(children, (child) => {
if (React.isValidElement(child)) {
return React.cloneElement(child, {
userRole: userRole,
...child.props
} as any);
}
return child;
})}
</div>
);
};
interface LevelBProps {
children: ReactNode;
userRole?: 'admin' | 'user';
}
const LevelB: React.FC<LevelBProps> = ({ children, userRole }) => {
// 继续传递给下一级
return (
<div className="level-b">
{React.Children.map(children, (child) => {
if (React.isValidElement(child)) {
return React.cloneElement(child, {
userRole: userRole,
...child.props
} as any);
}
return child;
})}
</div>
);
};
interface LevelCProps {
userRole?: 'admin' | 'user';
}
const LevelC: React.FC<LevelCProps> = ({ userRole }) => {
return <div>当前角色: {userRole}</div>;
};
// 使用示例
// <LevelA userRole="admin">
// <LevelB>
// <LevelC />
// </LevelB>
// </LevelA>
1️⃣3️⃣ 事件系统/事件总线
使用场景:兄弟组件间通信、解耦合通信
typescript
/**
* 场景:使用事件总线在不相关的组件间传递数据
*/
import React, { ReactNode, useEffect, useRef } from 'react';
// 简单的事件总线
class EventBus {
private listeners: { [key: string]: Function[] } = {};
on(event: string, callback: Function) {
if (!this.listeners[event]) {
this.listeners[event] = [];
}
this.listeners[event].push(callback);
}
off(event: string, callback: Function) {
if (this.listeners[event]) {
this.listeners[event] = this.listeners[event].filter((cb) => cb !== callback);
}
}
emit(event: string, data: any) {
if (this.listeners[event]) {
this.listeners[event].forEach((callback) => callback(data));
}
}
}
const eventBus = new EventBus();
// 发送者组件
const Sender: React.FC = () => {
const handleClick = () => {
// 发送事件和数据
eventBus.emit('user-login', { id: 1, name: 'Alice' });
};
return <button onClick={handleClick}>发送登录事件</button>;
};
// 接收者组件
interface ReceiverProps {
children: ReactNode;
}
const Receiver: React.FC<ReceiverProps> = ({ children }) => {
const callbackRef = useRef((data: any) => {
console.log('收到数据:', data);
});
useEffect(() => {
// 监听事件
eventBus.on('user-login', callbackRef.current);
return () => {
// 清理监听
eventBus.off('user-login', callbackRef.current);
};
}, []);
return <>{children}</>;
};
// 使用示例
// <div>
// <Sender />
// <Receiver>
// <UserProfile />
// </Receiver>
// </div>
1️⃣4️⃣ React Query / SWR(数据获取库)
使用场景:需要获取和共享异步数据
typescript
/**
* 场景:使用React Query获取数据并供children使用
* 注:这里是概念展示,实际需要安装react-query
*/
import React, { ReactNode } from 'react';
interface UserData {
id: number;
name: string;
}
interface DataProviderProps {
children: ReactNode;
}
// 模拟的DataProvider(类似useQuery的使用)
const DataProvider: React.FC<DataProviderProps> = ({ children }) => {
const [data, setData] = React.useState<UserData | null>(null);
const [loading, setLoading] = React.useState(true);
const [error, setError] = React.useState<string | null>(null);
React.useEffect(() => {
// 模拟异步数据获取
fetch('/api/user')
.then((res) => res.json())
.then((data) => {
setData(data);
setLoading(false);
})
.catch((err) => {
setError(err.message);
setLoading(false);
});
}, []);
// 通过children函数传递数据
return (
<>
{typeof children === 'function'
? (children as Function)({ data, loading, error })
: children}
</>
);
};
// 使用示例
// <DataProvider>
// {({ data, loading, error }) => (
// <>
// {loading && <p>加载中...</p>}
// {error && <p>错误: {error}</p>}
// {data && <p>用户: {data.name}</p>}
// </>
// )}
// </DataProvider>
1️⃣5️⃣ 状态管理库(Redux/Zustand/Recoil)
使用场景:大型应用、复杂的全局状态管理
typescript
/**
* 场景:使用Redux Store作为全局状态容器
*/
import React, { ReactNode } from 'react';
// 模拟Redux(实际使用react-redux库)
interface State {
user: { id: number; name: string } | null;
theme: 'light' | 'dark';
}
interface Action {
type: string;
payload?: any;
}
// Store
class Store {
private state: State = {
user: null,
theme: 'light'
};
private listeners: Function[] = [];
getState() {
return this.state;
}
subscribe(listener: Function) {
this.listeners.push(listener);
return () => {
this.listeners = this.listeners.filter((l) => l !== listener);
};
}
dispatch(action: Action) {
// 根据action更新state
if (action.type === 'SET_USER') {
this.state = { ...this.state, user: action.payload };
}
// 通知所有监听者
this.listeners.forEach((listener) => listener());
}
}
const store = new Store();
// Provider组件
interface StoreProviderProps {
children: ReactNode;
store: Store;
}
const StoreProvider: React.FC<StoreProviderProps> = ({ children, store }) => {
return (
<div>
{/* 将store提供给所有children */}
{children}
</div>
);
};
// 使用示例
// <StoreProvider store={store}>
// <UserProfile />
// <ThemeSwitcher />
// </StoreProvider>
1️⃣6️⃣ Slot 模式(Vue中常见的模式)
使用场景:模板插槽,允许自定义内容区域
typescript
/**
* 场景:Card组件的多个插槽
*/
import React, { ReactNode } from 'react';
interface CardSlots {
header?: ReactNode;
body?: ReactNode;
footer?: ReactNode;
actions?: ReactNode;
}
interface CardProps {
children?: ReactNode;
slots?: CardSlots;
}
const Card: React.FC<CardProps> = ({ children, slots }) => {
// 如果提供了slots,使用slots;否则使用children
return (
<div className="card">
{slots?.header && (
<div className="card-header">
{slots.header}
</div>
)}
<div className="card-body">
{slots?.body || children}
</div>
{slots?.actions && (
<div className="card-actions">
{slots.actions}
</div>
)}
{slots?.footer && (
<div className="card-footer">
{slots.footer}
</div>
)}
</div>
);
};
// 使用示例
// <Card
// slots={{
// header: <h2>标题</h2>,
// body: <p>内容</p>,
// actions: <button>操作</button>,
// footer: <small>页脚</small>
// }}
// />
1️⃣7️⃣ ref.current 直接操作(不推荐)
使用场景:需要直接操作DOM或调用子组件方法
typescript
/**
* 场景:直接通过ref操作子组件
* 注:尽量避免,应该优先使用props或Context
*/
import React, { useRef, ReactNode } from 'react';
interface ScrollableProps {
children: ReactNode;
}
const Scrollable = React.forwardRef<HTMLDivElement, ScrollableProps>(
({ children }, ref) => {
return (
<div
ref={ref}
style={{ height: '300px', overflow: 'auto' }}
>
{children}
</div>
);
}
);
Scrollable.displayName = 'Scrollable';
// 使用示例
const ScrollableExample: React.FC = () => {
const scrollRef = useRef<HTMLDivElement>(null);
const handleScroll = () => {
if (scrollRef.current) {
// 直接操作DOM
scrollRef.current.scrollTop = 0;
}
};
return (
<>
<button onClick={handleScroll}>回到顶部</button>
<Scrollable ref={scrollRef}>
{/* 长内容 */}
</Scrollable>
</>
);
};
📊 完整对比表
| 方式 | 跨级传值 | 性能 | 复杂度 | 推荐指数 | 主要场景 |
|---|---|---|---|---|---|
| Context API | ✅ 优秀 | ⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | 全局状态、主题、语言 |
| CloneElement | ❌ | ⭐⭐⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐ | 统一修改子组件props |
| Render Props | ✅ | ⭐⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐ | 灵活渲染、访问父状态 |
| useImperativeHandle | ❌ | ⭐⭐⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐ | 命令式操作 |
| HOC | ❌ | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐ | 功能增强、代码复用 |
| 复合组件 | ✅ | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ | 强关联组件库 |
| useContext | ✅ | ⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐ | 访问Context值 |
| Props Drilling | ⚠️ 有限 | ⭐⭐⭐⭐⭐ | ⭐ | ⭐ | 简单层级传递 |
| 事件系统 | ✅ | ⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐ | 解耦通信、兄弟组件 |
| 数据获取库 | ✅ | ⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐ | 异步数据管理 |
| 状态管理库 | ✅ | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | 大型应用全局状态 |
✅ 最佳实践建议
- 优先使用 Context - 大多数全局状态场景
- 使用 CloneElement - 需要修改所有子组件props
- 使用 Render Props - children需要访问父组件状态
- 使用复合组件 - 组件间有强关联
- 避免 Props Drilling - 超过3层就考虑Context
- 谨慎使用 HOC - 更推荐使用Hooks
- 避免事件总线 - 除非真的需要解耦
希望这份完整指南能帮助您理解React中所有给children传值的方式!