You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在React+TypeScript中向children传递render props?

解决Accordion组件传递open属性给子组件的TypeScript类型问题

你的核心问题是当前Accordion定义的children为render prop函数,但App中传入的是普通React元素,类型不兼容,同时需要把open属性传递给AccordionContent。下面提供两种可行方案:


方案一:使用Render Props模式(类型匹配写法)

这种方案需要统一组件的使用方式,让子组件通过函数接收isOpen参数。

修正Accordion.tsx的类型与逻辑

import React from 'react';

// 定义传递给子组件的参数类型
interface RenderPropParams {
  isOpen: boolean;
}

interface AccordionProps {
  open?: boolean;
  // children是接收isOpen的函数,返回React节点
  children: (props: RenderPropParams) => React.ReactNode;
}

const Accordion = ({ open = false, children }: AccordionProps) => {
  // 直接调用children函数,传入open值作为isOpen
  return (
    <div className="flex flex-col border border-gray-600">
      {children({ isOpen: open })}
    </div>
  );
};

export default Accordion;

修改App.tsx的使用方式

将Accordion的children写成函数,接收isOpen后传递给AccordionContent:

const App = () => {
  return (
    <Accordion open={true}>
      {({ isOpen }) => (
        <>
          <AccordionTitle title="First Accordion" />
          {/* 把isOpen传递给AccordionContent */}
          <AccordionContent isOpen={isOpen}>
            <p>
              Lorem Ipsum including versions of Lorem Ipsum.
            </p>
          </AccordionContent>
        </>
      )}
    </Accordion>
  );
};

给AccordionContent添加类型

interface AccordionContentProps {
  isOpen: boolean;
  children: React.ReactNode;
}

const AccordionContent = ({ isOpen, children }: AccordionContentProps) => {
  return (
    <div className={isOpen ? 'block' : 'hidden'}>
      {children}
    </div>
  );
};

方案二:遍历子元素自动注入属性(保持App原有写法)

如果想保留App中直接嵌套子组件的写法,可以通过遍历子元素,给AccordionContent自动注入isOpen属性。

修正Accordion.tsx

import React, { ReactElement } from 'react';

// 先定义AccordionContent的属性类型
interface AccordionContentProps {
  isOpen?: boolean;
  children: React.ReactNode;
}

// 辅助函数:判断是否为AccordionContent组件
const isAccordionContent = (child: React.ReactNode): child is ReactElement<AccordionContentProps> => {
  return React.isValidElement(child) && child.type === AccordionContent;
};

interface AccordionProps {
  open?: boolean;
  // children为普通React节点数组
  children: React.ReactNode;
}

const Accordion = ({ open = false, children }: AccordionProps) => {
  // 遍历子元素,给AccordionContent添加isOpen属性
  const transformedChildren = React.Children.map(children, (child) => {
    if (isAccordionContent(child)) {
      return React.cloneElement(child, { isOpen: open });
    }
    return child;
  });

  return (
    <div className="flex flex-col border border-gray-600">
      {transformedChildren}
    </div>
  );
};

export default Accordion;

App.tsx保持原有写法不变

const App = () => {
  return (
    <Accordion open={true}>
      <AccordionTitle title="First Accordion" />
      <AccordionContent>
        <p>
          Lorem Ipsum including versions of Lorem Ipsum.
        </p>
      </AccordionContent>
    </Accordion>
  );
};

给AccordionContent添加类型

interface AccordionContentProps {
  isOpen?: boolean;
  children: React.ReactNode;
}

const AccordionContent = ({ isOpen = false, children }: AccordionContentProps) => {
  return (
    <div className={isOpen ? 'block' : 'hidden'}>
      {children}
    </div>
  );
};

两种方案对比:

  • 方案一更灵活,适合需要给多个子组件传递isOpen的场景;
  • 方案二更贴近你原本的写法,侵入性低,适合仅给特定子组件传递属性的场景。

内容的提问来源于stack exchange,提问作者Ajitesh Chhatani

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 06:25:05