Reputation: 341
I'm trying to dynamically change an element name for reuse of a function.
static renderDetails(props, parentTableElementOpen, parentTableElementClose, ) {
let coverageRows;
if (props.length !== 0) {
return (
<span>
{parentTableElementOpen}
{props.map((columnData, index) => {
if (index === props.length - 1) {
coverageRows = (<TableRowCol classNames={styles.text_align_right}>{columnData}</TableRowCol>);
}
else {
coverageRows = (<TableRowCol>{columnData}</TableRowCol>);
}
return coverageRows;
})}
{parentTableElementClose}
</span>
);
}
return null;
}
The call to this function is below.
Utils.renderDetails(this.props.columnData, '<TableRow>', '</TableRow>');
The parentTableElementOpen
and parentTableElementClose
will have the names of the elements I'm after.
The rendered page doesn't seem to recognize them and instead of a <TableRow> </TableRow> element type
it renders just text <TableRow> </TableRow>
Maybe a bit tricky or overly complicated what I'm trying to do here but thought it could be a good refactor between 2 identical functions.
Upvotes: 0
Views: 71
Reputation: 4687
There might be a solution that actually could work in the way you described but I think you're thinking of this using an HTML mindset. Keep in mind that with React you're rendering a Component
which is not an HTML Tag/XML even though it shares similarities with the syntax.
In your case you're passing a string so it is rendering a string.
I think what you want is a generic component that renders the children, not a function that tries to pick a component. Maybe something like this:
class MyTableRow extends React.Component {
render() {
return ( //do whatever customization you want here.
<TableRowCol>
{this.props.children} //renders what's "inside" the tag. You can pass this or specify it in the JSX
</TableRowCol>
)
}
}
If you think about what you're doing in that utility call you're actually specifying the tag you want to use and then just passing props which in the world of React is identical to:
//Some render function
...
<MyUtilityObject props={props} />
...
My first instinct would be to "invert" the design to use components as that seems to be how React is designed.
EDIT I didn't realize that element.props.children was readonly so the idea below isn't going to work.
My suggestion in this case would be as above. In general this abstract method really isn't doing anything and could be refactored into a custom component so instead of a function call you use the component
<MyTable>
{ row.map( (row, index) => {
switch(row.type) {
case 'data1':
return <MyCustomRow row={row} key={index} />
case 'data2':
return <MyCustomRow2 row={row} key={index} />
default:
return null
}
})
</MyTable>
NOPE
Now that being said, if you wanted to maintain this signature and you have a good reason what you probably want to do is this:
static renderDetails(props, parentElement) {
if(props.length === 0) {
return null; //nothing to see here!
}
let coverageRows;
let children = props.map((columnData, index) => {
if (index === props.length - 1) {
coverageRows = (<TableRowCol classNames={styles.text_align_right}>{columnData}</TableRowCol>);
}
else {
coverageRows = (<TableRowCol>{columnData}</TableRowCol>);
}
return coverageRows;
})
parentElement.children = children
return <span>parentElment</span> //I'm not sure why you need the span, but if you do great. I would just return the parentElement
}
//Called by...
render() {
...
renderDetails(props, <TableRow />)//an actual table row instance, not the tag name as a string
...
}
I didn't test any of this but it should get you moving in the right direction. I would recommend writing a custom component that renders children so you understand how that works. It will save you a lot of time down the road.
Upvotes: 1