9

Question

How can I confirm that a react element received through props (like children for example) is of a given type in my render method?

Example:

Say I have a List element and a ListItem element. In the render method of List, I want to look for all of the children that were passed and do something special with any children that are ListItems.

I did find an implementation that works, but only after trial and error. See the code below. (React 15.4.2)

List.jsx

import ListItem from 'list-item';

...

React.Children.map(children, child => {
  console.log(child);     // function ListItem() { ... }
  console.log(ListItem);  // function ListItem() { ... }
  
  if (isListItem(child)) {
    return (...);
  }
  return child;
})

// this implementation does not work
isListItem(element) {
  return (element.type === ListItem);
}

// this implementation does work, but might break if I'm using something like uglify or if I use `react-redux` and `connect()` ListItem (as that will change the display name)
isListItem(element) {
  return (element.type.displayName === 'ListItem');
}

// this implementation does work
isListItem(element) {
  return (element.type === (<ListItem />).type);
}

ListItem.jsx

class ListItem expends React.component {
  ...
}

export default ListItem;

So, the last implementation seems to work, but why doesn't the first implementation work? I can't find any material relating to this in the react documentation, though I did find some stack overflow questions about the same thing. The answers provided in those questions, however, indicate that the first implementation should work (though they are for older versions of React)

Relevant Links

Community
  • 1
  • 1
Luke
  • 5,567
  • 4
  • 37
  • 66
  • Do you have redux over these elements? If so it could be one of the reasons. Other that comes to mind is some of these are not really the components themselves. `ListItem` is a module in this case whereas `` is component. – Fma Mar 13 '17 at 17:43
  • @Fma I don't have redux wrapping withe component in the example above. `ListItem` is the default export of the `list-item` module. So, should that import as I have it be importing the element? As I show, when I log the `ListItem` object it seems to be the same function as the element. – Luke Mar 13 '17 at 17:52
  • Could you tell me in which part are you doing check part (`React.Children.map`) – Fma Mar 13 '17 at 17:57
  • @Fma That is in the render function of the `List` component – Luke Mar 13 '17 at 17:59
  • I wrote a one and checked and funny thing is all 3 works :) Btw it is extends right? – Fma Mar 13 '17 at 18:07
  • @Fma That is weird. Which version of React are you using? Are both components defined in the same file or separate files? – Luke Mar 13 '17 at 18:09
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/137959/discussion-between-fma-and-lukep). – Fma Mar 13 '17 at 18:10

1 Answers1

1

While this question is old, I ran into this problem while using react-hot-loader and took me a while to finally find this GitHub issue explaining why it behaved this way.

This is intended, react-hot-loader@3 patches React.createElement(<ImportedComponent />) is equivalent to React.createElement(ImportedComponent) so that it returns an element of a proxy wrapper for your components instead of the original component, this is part of allows to replace methods on the component without unmounting.

- @nfcampos

In addition to the methods you discovered, RHL now provides a areComponentsEqual() function with a dedicated section in their README.

import { areComponentsEqual } from 'react-hot-loader'

const element = <Component />
areComponentsEqual(element.type, Component) // true
allejo
  • 2,076
  • 4
  • 25
  • 40