4

I want on every component in my app to add attribute component-name="componentX". I don't want to do it hard coded when creating a component but to find a generic way to find the component name and set it in the attribute.

I know there is the displayName property but it's only for class component.

I have a lot of functional components. How can I achieve it?

Thanks!

einav
  • 599
  • 3
  • 8
  • 15
  • Display can be set on functional components as well. Refer to https://stackoverflow.com/questions/43356073/how-to-set-displayname-in-a-functional-component-react – Shubham Gupta Sep 23 '18 at 11:30

1 Answers1

6

If you wrap children you can access the child.type.name to get the component / function name.

Here is a small example:

class LogNames extends React.Component {
  render() {
    const { children } = this.props;
    React.Children.forEach(children,child =>{
      console.log(child.type.name)
    });
    return children;
  }
}

class Child extends React.Component {
  render() {
    return <div>A Child</div>
  }
}

const Child2 = () => <div>Child 2</div>

class App extends React.Component {
  render() {
    return (
      <div>
        <LogNames>
          <Child/>
        </LogNames>
        <LogNames>
          <Child2 />
        </LogNames>
      </div>
    );
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root" />

Just noticed you want to set an attribute on the DOM as well, so i added another example that does just that (open devtools to see the attributes):

class WithNameAttr extends React.Component {

  componentDidMount(){
    const {children} = this.props;

    // get a ref to the current node
    const node = ReactDOM.findDOMNode(this);

    // force and return a signle child
    const child = React.Children.only(children);

    // set name attribute (if available) 
    const name = child.type.name;
    name && node.setAttribute('component-name', name);
  }

  render() {
    return this.props.children;
  }
}

class Child extends React.Component {
  render() {
    return <div>A Child</div>
  }
}

const Child2 = () => <div>Child 2</div>

class App extends React.Component {
  render() {
    return (
      <div>
        <WithNameAttr>
          <Child />
        </WithNameAttr>
        <WithNameAttr>
          <Child2 />
        </WithNameAttr>
        <WithNameAttr>
          <div>dom elemetns doesnt have names</div>
        </WithNameAttr>
      </div>
    );
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"/>
Sagiv b.g
  • 30,379
  • 9
  • 68
  • 99
  • Question out of curiosity, what is the difference between `type.name` and `displayName`? Because from experience I have encountered problems with `type.name` as it changed after builds. – Tomas Eglinskas Sep 23 '18 at 22:15
  • 1
    @TomasEglinskas Not sure where do you see the `displayName` (i think it has been changed since react 15, maybe you mean `constructor.name`)? anyway don't forget we are referencing a child here (that can also be a function component and not a class) – Sagiv b.g Sep 24 '18 at 18:19