Estoy tratando de crear un componente de tabla donde el componente servirá algún nombre de clase especial para sus hijos específicos.
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> ); };
Este es mi componente y quiero usarlo así.
<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>
Pero aquí el problema es que mi función Children.map solo recorre sus hijos inmediatos. ¿Cómo paso accesorios a su hijo anidado (th, td, etc.)
Puede definir una función recursiva para iterar sobre todos los elementos secundarios hasta que este elemento secundario sea null
o sea de tipo string
o cualquier otra condición según sus requisitos, aquí hay un ejemplo:
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>
Puede proporcionar elementos children
después de aplicar classNames
al elemento child
actual. Puede definir otra función para aplicar nombres de clase personalizados según sus necesidades (la lógica se puede cambiar según sus necesidades).
Esto también funcionaría.
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> ); };