0

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.

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

5 Comments

Thanks for all this @Daniel B. Chapman. I'm getting 2 errors if I could get your input?
TypeError: can't define property "children": Object is not extensible
for parentElement.children = children; I get but maybe less important as its from eslint 'no param-re-assign'
@Darren It looks like I steered you in a bad direction. The element.props.children object is Read Only so it won't do what you want it to do. I'll updated my answer.
Thank you for all your help, got it working using a generic component but kept the reusable function, however I took the switch example you had and was able to then run with only one function now and have it handle the dynamic switching between component types. Very pleased with the result.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.