0

I have a component which renders "react-icons" object. However, if no icon is supplied I want to display "NoIcon" string on the UI.

The component A is as such.

component A

import React from 'react';
import { FaHeart} from "react-icons/fa";

const Icon = ({FaIcon = "NoIcon"}) => {
  return (
    <div>
    <FaIcon/>
    </div>
    );
};

export default Icon;

and calling this component from another components B works :

component B

import React from 'react';
import Icon from './components/icons/icon';
import { FaHeartBroken } from "react-icons/fa";

class App extends React.Component {  
    render(){
        return(
              <Icon FaIcon={ FaHeartBroken }/>
        )      
    }   
}
export default App;

this returns a "Broken Heart Icon" i.e 💔.


But, if no icon is supplied in component B it should return a text i.e "NoIcon" in the UI.

Component B

....
....
      <Icon FaIcon/>
....

however this raises an error

Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: boolean.

Check the render method of `Icon`.

I also tried to set an or method on component A for value assignment, which did not work either. Why providing no argument within Icon component, calling for a Boolean check?

component A

const Icon = ({FaIcon = FaHeart || "NoIcon"}) => {
    ....

Also tried these variations. These do not raise any error but do not return any value on the UI either.

component B

...
 <Icon/>
 <Icon FaIcon = "Test"/>
 <Icon FaIcon = {"Test"}/>

How do we resolve this?

1 Answer 1

3

A prop without a value <Foo bar /> is actually shorthand for <Foo bar={true} />.

So this:

 <Icon FaIcon/>

Is not correct. And if you read that error again, it probably makes more sense now:

Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: boolean.

This means that it was expecting a a string/class/function, but got a boolean value instead. In this case true from the prop shorthand value.

This means that how you omit that prop, then you get the default.

 <Icon />

Secondly, this won't work:

const Icon = ({FaIcon = "NoIcon"}) => {
  return (
    <div>
    <FaIcon/>
    </div>
    );
};

To render something custom as JSX it must be a component. The import from react-icons/fa is a component, but the string "NoIcon" is not.

I think in this case it may be simpler to have a conditional that renders an icon if the prop is present, or a string if it is not.

Something like:

const Icon = ({FaIcon}) => {
  return (
    <div>
      { FaIcon ? <FaIcon/> : "NoIcon" }
    </div>
  );
};

If you want one prop to handle an icon component or a string you could do this in a few ways. But if you want to be able to pass in icon component, or a string, then you do something like:

const Icon = ({FaIcon = "NoIcon"}) => {
  return (
    <div>
      { typeof FaIcon === 'string' ? FaIcon : <FaIcon/>  }
    </div>
  );
};

In this case if the prop is a string (which applies to the default of "NoIcon" as well) then render it as a string. Otherwise assume it's a component and render it.

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

4 Comments

while this is correct, I'm pretty sure that after this fix the code will not "work fine as is". The default also needs to be a component - NoIcon, rather than a string "NoIcon"
Heh, yeah just noticed that myself :) Updated
Thanks @AlexWayne. Say in a situation I want to rather pass a custom text, e.g <Icon FaIcon = "Test"/> or <Icon FaIcon = {"Test"}/> how can I do that? Please check the update example around the end of the question.
@everestial007 See my update at the end of my answer.

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.