Sebastian Olsen
Sebastian Olsen

Reputation: 10878

How to get children type in react

I'm trying to make my own Tabs component, so that I can use tabs in my app. However I seem to be having issues trying to extract the child components I need by type.

import React from 'react'

export class Tabs extends React.Component {
  render() {
    let children = this.props.children
    let tablinks = React.Children.map(children, x => {
      console.log(x.type.displayName) // Always undefined
      if (x.type.displayName == 'Tab Link') {
        return x
      }
    })

    return (
      <div className="tabs"></div>
    )
  }
}

export class TabLink extends React.Component {
  constructor(props) {
    super(props)
    this.displayName = 'Tab Link'
  }
  render() {
    return (
      <div className="tab-link"></div>
    )
  }
}

<Tabs>
    <TabLink path="tab1">Test</TabLink>
    <TabLink path="tab2">Test2</TabLink>
</Tabs>

My console.log never returns "Tab Link", it always returns undefined, why?

Upvotes: 8

Views: 15741

Answers (4)

Leandro Ortiz
Leandro Ortiz

Reputation: 441

I'm wondering why does your Tabs component need to know how to render each children.

You could have a specific component for each type of tab, with their own styles and with 2 props: isSelected and onSelect.

Then the Tabs would only:

  1. Render its children, inline, with the correct space among them ("display:flex" with column-gap)
  2. Control the tab selection, by keeping the state of the selected tab and handling the onSelect of each tab (to update the selectedTab state and to pass true in the isSelected prop of the correct tab)

Upvotes: 0

Salim
Salim

Reputation: 2546

You can use the already defined name property:

if (x.type.name === TabLink.name) {
    return x
}

I recommend to use TabLink.name instead of 'TabLink' string for better maintenance.

See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name

Upvotes: 3

Lyubomir
Lyubomir

Reputation: 20027

As an alternative you could use

console.log(x.type.name) // this would be 'TabLink'

You don't need to explicitly define displayName in this case.

https://jsfiddle.net/lustoykov/u1twznw7/1/

Upvotes: 14

QoP
QoP

Reputation: 28397

It's undefined because displayName should be a static property.

class TabLink extends React.Component { 
  constructor(props) {
    super(props)
  }
  render() {
    return (
      <div className="tab-link"></div>
    )
  }
} 
TabLink.displayName = 'Tab Link'

jsfiddle (check the console)

Upvotes: 3

Related Questions