循环遍历 React Children 的每个嵌套子级

Has*_*rak 6 javascript reactjs

我正在尝试创建一个表组件,该组件将为其特定子组件提供一些特殊的类名。

    const BasicTable = ({ children }) => {
        const RenderChild = Children.map(children, (el) => {
            const child = el;
    
            if (child !== null) {
                if (child.props.originalType !== "th") {
                    return <child.type {...child.props} className="th" />;
                }
    
                return <child.type {...child.props} />;
            }
            return null;
        });
    
        return (
            <div className="table-responsive">
                <table className="table w-full bg-transparent">{RenderChild}</table>
            </div>
        );
    };
Run Code Online (Sandbox Code Playgroud)

这是我的组件,我想像这样使用它。

    <BasicTable>
        <thead>
            <tr>
                <th>ID</th>
                <th>Name</th>
                <th>Position</th>
                <th>Salary</th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td>dsfa</td>
                <td>dsfa</td>
                <td>dsfa</td>
                <td>dsfa</td>
            </tr>
        </tbody>
    </BasicTable>
Run Code Online (Sandbox Code Playgroud)

但这里的问题是我的Children.map函数仅循环其直接子级。如何将 props 传递给其嵌套子级(th、td、...等)

Ami*_*era 5

您可以在将 应用于当前children后提供 prop 。您可以定义另一个函数来根据您的需要应用自定义类名称(可以根据您的需要更改逻辑)。classNameschild

这也行得通。

import { Children, isValidElement } from "react";

const BasicTable = ({ children }) => {
  const RenderChild = (children) => {
    return Children.map(children, (child) => {
      if (isValidElement(child)) {
        return (
          <child.type
            {...child.props}
            children={RenderChild(child.props.children)}
            className={resolveCalssName(child.type)}
          />
        );
      }
      // non react elements (text inside the table ...etc)
      return child;
    });
  };

  const resolveCalssName = (type) => {
    switch (type) {
      case "thead":
        return "custom-thead-class-name";
      case "tbody":
        return "custom-tbody-class-name";
      case "tr":
        return "custom-tr-class-name";
      case "th":
        return "custom-th-class-name";
      case "td":
        return "custom-td-class-name";
      default:
        return "";
    }
  };

  return (
    <div className="table-responsive">
      <table className="table w-full bg-transparent">
        {RenderChild(children)}
      </table>
    </div>
  );
};
Run Code Online (Sandbox Code Playgroud)

代码沙箱


Sae*_*loo 3

您可以定义一个递归函数来迭代所有子级,直到该子级是null或属于类型string或根据您的要求的任何其他条件,这里是一个示例:

const BasicTable = ({ children }) => {

  const iterateOverChildren = (children) => {
    return React.Children.map(children, (child) => {
      // equal to (if (child == null || typeof child == 'string'))
      if (!React.isValidElement(child)) return child;

      return React.cloneElement(child, {
        ...child.props,
        // you can alse read child original className by child.props.className
        className: child.type == 'th' ? 'th' : '',
        children: iterateOverChildren(child.props.children)})
    })
  };

  return (
    <div className="table-responsive">
      <table className="table w-full bg-transparent">
        {iterateOverChildren(children)}
      </table>
    </div>
  );
};

function App() {
  return (
      <BasicTable>
        <thead>
          <tr>
            <th>ID</th>
            <th>Name</th>
            <th>Position</th>
            <th>Salary</th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td>dsfa</td>
            <td>dsfa</td>
            <td>dsfa</td>
            <td>dsfa</td>
          </tr>
        </tbody>
      </BasicTable>
  );
}


ReactDOM.render(<App/>, document.getElementById('root'))
Run Code Online (Sandbox Code Playgroud)
.th{
  color: green;
}
Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>

<div id="root"></div>
Run Code Online (Sandbox Code Playgroud)