Lars Flieger
Lars Flieger

Reputation: 2562

Can I create a condition to render an React component / element?

I would like to render a component based on a prop.

const Item = ({ property }) => {

  return property ? <h1>...</h1> : <h6>...</h6>

}

In my code there is parent elements and child elements for the element. So I was wondering if something like this is possible:

const Item = ({ property }) => {
  element = property ? <h1> : <h6>
  return <element>...</element>
}

I know that I can wrap the parent + child component but I'm looking for a more readable and maintainable solution.

Here is my component:

import { IconProp } from "@fortawesome/fontawesome-svg-core"
import { faFolder } from "@fortawesome/free-solid-svg-icons"
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
import { Link } from "react-router-dom"

type ListItemProps = {
    /** Set to true if element should have background */
    background?: boolean
    /** Set to true if element should be indented */
    indent?: boolean
    /** Title of an List Element is at the left side */
    title: string
    /** Icon at the beginning of the Element */
    icon?: IconProp
    /** Content on the left side next to title */
    header?: React.ReactChild
    /** Link to when click element */
    to?: string
    /** Function what happens when you click element */
    onClick?: (values: any) => void
}

/**
 * List, should have List as parent
 */
export const ListItem: React.FC<ListItemProps> = ({ title, icon = faFolder, indent, background, header, children, to, onClick }) => {

    // Elements on the left side of the item
    const headerContent = <>
        <FontAwesomeIcon icon={icon} className="text-lightgrey mr-4" />
        <h4 className="text-lg text-headline-black font-semibold mr-4">{title}</h4>
        {header}
    </>

    const headerClasses = `flex items-center py-4 pl-7 ${indent ? "pl-16" : ""} flex-grow`

    return <div className={`flex rounded-lg w-full cursor-pointer ${background ? "bg-white-lightgrey hover:bg-gray-200" : "hover:bg-white-lightgrey"}`}>
        {to ?
            <Link to={to} className={headerClasses}>
                {headerContent}
            </Link>
            :
            <button onClick={onClick} className={headerClasses}>
                {headerContent}
            </button>
        }
        {children && <div className="flex items-center mx-4">
            {children}
        </div>}
    </div>
}

Upvotes: 1

Views: 260

Answers (1)

Danny Harding
Danny Harding

Reputation: 1745

There are 2 options for doing this:

  1. Use a dynamic element similar to the pseudocode you shared. You can conditionally pick the element, you just need to use the name of the tag as a string like this (disclaimer: I don't know how conventional this is)

Note: the variable name for the component (in this example Component) needs to be capitalized or accessed with dot notation. <Component /> or <someObject.component /> will work, but <component /> will not.

function Item({prop}) {
   const Component = prop ? 'h1' : 'h6'

   return <Component>
      <div>It works!</div>
   </Component>
}

This solution also works for custom react components instead of HTML tags. That looks like this

function FuncComponent() {}

function OtherComponent() {}

function Item({prop}) {
   const Component = prop ? FuncComponent : OtherComponent

   return <Component>
      <div>It works!</div>
   </Component>
}
  1. Render the children first before the return statement, and then provide that as children to the element you want
function Item({prop}) {
   const children = <div>It works!</div>

   return {prop ? <h1>{children}</h1> : <h6>{children}</h6>}
}

All of these will work, it's just up to you which you prefer.

Upvotes: 3

Related Questions