0

Update: Solution below

I'm trying to make these icons from my data file appear, but it's showing [object object] and then undefined for the data that doesn't have any icons

Here is what I wrote that shows the errors

    <div>
      {dropdown ? `${item.iconClosed}` : `${item.iconOpened}`}
    </div>

Basically I want the icons to only show if dropdown menu is opened or closed.

If I just do

    <div>{item.iconClosed}</div>

it shows up completely fine. But when I try to add an if or else statement I can't seem to figure out the proper way to write it

Note in the data file, it's just an icon as the value

   iconClosed: <RiIcons.RiArrowDownSFill />,
   iconOpened: <RiIcons.RiArrowUpSFill />,

Also, I have data that does not have any icons, so how would I write the logic to only show these icons if the value exist or not?

My logic was this

if(dropdown) {
show upArrow
} else if(dropdown === false) {
show downArrow
} else {
 show null
 }

My issue is how would I write this as a ternary operator inside of my div?

<div>{dropdown && dataContainsDropdown ? "downArrow" : " "}</div>

The problem here is that I can't check if the dropdown is open and to show the upArrow

Updated answer that worked

   <div>
      {item.dropDown && dropdown
        ? item.iconOpened
        : item.dropDown
        ? item.iconClosed
        : null}
    </div>
4
  • how dropdown changes its state? Commented Nov 27, 2020 at 17:17
  • if I do {item.dropDown ? 'upArrow' : ' '} then it will show the arrow icon for data that only contains dropdown data. But the dropdown gets triggered when I click on the main menu item Commented Nov 27, 2020 at 17:18
  • What are the possible values of dropdown? Your question does not make that clear. Commented Nov 27, 2020 at 17:19
  • I found a solution and added the updated code below, but I had to manually add the icons. I still don't know the proper way to pass the icon values from my data file instead of hard coding them above Commented Nov 27, 2020 at 17:23

3 Answers 3

4
dropdown ? `${item.iconClosed}` : `${item.iconOpened}`

The problem here is that you put your icon into a template string, so the result will be a string (later added to the DOM). Since your icon is an object, it will be stringified using the default Object toString method which returns "[Object object]"

You don't need template string at all here so just do:

dropdown ? item.iconClosed : item.iconOpened

edit: you can combine more than one condition with logical AND/OR before the ? if you want to make sure your item has icons

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

Comments

2

You're getting [object Object] because you're trying to render an object as a string.

    <div>
      {/* if item.iconClosed is a React element, don't put it in a string */}
      {dropdown ? `${item.iconClosed}` : `${item.iconOpened}`}
      {/* just use it directly as the evaluated result of your ternary */}
      {dropdown ? item.iconClosed : item.iconOpened}
    </div>

Now if you want handle the case where there's no icon, either for closed or open, you could do this.

function MyComponent() {
  // ...other component code
  let icon = dropdown ? item.iconClosed : item.iconOpened
  icon = !icon ? null : icon
  
  return (
    // ...other jsx returned from element
    <div>{icon}</div>
  )
}

Now, there are some other things here that are not very idiomatic for React, but I won't go into those unless you'd like me to.

3 Comments

+1 for the tests out of the render. Also if OP is sure that an undefined icon is either undefined or null the fallback check is unnecessary since React won't render these values.
Yes, but since you cannot return undefined from a component, I find it's better to stick to a single empty value, null, when working in React. This way, if you refactor, and something that was previously a value within some other JSX becomes the return of a component, it won't break.
You cannot return undefined from a component, but using undefined within JSX is no problem. <p>{undefined}</p> renders an empty <p> element. If you really want to stick to null you could replace icon = !icon ? null : icon with icon ||= null assuming your Babel is up to date. See: Logical OR assignment
0

The problem is that from each JSX template the compiler creates an object with all the information React needs to create that node [1]. So when you use any of them in a template string it calls .toString which returns [object Object]. For solving your problem just get rid of template strings:

    <div>
      {dropdown ? `${item.iconClosed}` : `${item.iconOpened}`}
    </div>

[1] the reality is that the compiler just calls a function provided by React which creates the object needed.

Comments

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.