【问题标题】:Loop through every nested child of React Children循环遍历 React Children 的每个嵌套子节点
【发布时间】:2022-01-12 04:42:15
【问题描述】:

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

    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>
        );
    };

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

    <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>

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

【问题讨论】:

  • 认为您必须检查子组件是否有其子组件并执行您想要的操作。例如,如果您正在迭代 thead,请检查 thead 是否有孩子,如果有,您可以执行您需要的操作

标签: javascript reactjs


【解决方案1】:

您可以定义一个递归函数来遍历所有子级,直到该子级为 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'))
.th{
  color: green;
}
<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>

【讨论】:

    【解决方案2】:

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

    这也行。

    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>
      );
    };
    

    Code sandbox

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-06-29
      • 1970-01-01
      • 1970-01-01
      • 2011-09-11
      • 2021-11-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多