react中 所有给 children 传值的方式

我为您整理一份更加全面的所有给 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 ⚠️ 有限 ⭐⭐⭐⭐⭐ 简单层级传递
事件系统 ⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐ 解耦通信、兄弟组件
数据获取库 ⭐⭐ ⭐⭐ ⭐⭐⭐⭐ 异步数据管理
状态管理库 ⭐⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐ 大型应用全局状态

✅ 最佳实践建议

  1. 优先使用 Context - 大多数全局状态场景
  2. 使用 CloneElement - 需要修改所有子组件props
  3. 使用 Render Props - children需要访问父组件状态
  4. 使用复合组件 - 组件间有强关联
  5. 避免 Props Drilling - 超过3层就考虑Context
  6. 谨慎使用 HOC - 更推荐使用Hooks
  7. 避免事件总线 - 除非真的需要解耦

希望这份完整指南能帮助您理解React中所有给children传值的方式!

相关推荐
加蓓努力我先飞3 小时前
Vue3小兔鲜-(二)
前端·javascript·css·vue3
豆苗学前端3 小时前
企业级用户登录Token存储最佳实践,吊打面试官
前端·javascript·后端
李剑一3 小时前
vite框架下大屏适配方案
前端·vue.js·响应式设计
有点笨的蛋3 小时前
HTML5 敲击乐:从静态页面到动态交互的前端实战
前端·html
文心快码BaiduComate3 小时前
冰城码力全开,共赴AI Coding英雄之旅!CEDxCNCC百度文心快码Meetup圆满落幕!
前端·后端·程序员
社恐的下水道蟑螂3 小时前
用CSS3拍一部《星球大战》片头?前端导演的"原力"修炼指南
前端·javascript
子非鱼3733 小时前
git 常用命令行
前端
Tzarevich3 小时前
CSS3星球大战:前端代码界的视觉导演艺术
前端·css
BBB努力学习程序设计3 小时前
CSS复合选择器
前端·html