BlogReactJS

Joining arrays with JSX and React components

Written by Codemzy on June 9th, 2023

If you want to join React components together with JSX or another component - for example, in a list or breadcrumb - you might get [object Object] when using Array.join(). Here's what you can do instead.

I was recently building a breadcrumb component for a React app, something that looked a bit a like this:

breadcrumb example with React separator

Those ">" symbols are SVG icons, and I have a React component for it called BreadcrumbIcon.

function BreadcrumbIcon() {
  return (
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" height="18" width="18"><path d="M12.1717 12.0005L9.34326 9.17203L10.7575 7.75781L15.0001 12.0005L10.7575 16.2431L9.34326 14.8289L12.1717 12.0005Z"></path></svg>
  );
};

I use it like this:

function Breadcrumb(props) {
  return (
    <div>Home <BreadcrumbIcon /> Account <BreadcrumbIcon /> Settings</div>
  );
};

And that's perfect for one breadcrumb. But I want to reuse the Breadcrumb component throughout the app, so instead of hard coding the crumbs, I need to pass in a "crumbs" prop so I can return the right paths for each page.

I'll pass the crumbs prop as an array.

<Breadcrumb crumbs={[ "Home", "Account", "Settings" ]} />

And then I can join the array together, with the divider icon in between each item.

function Breadcrumb({ crumbs }) {
  return (
    // join the crumbs
  );
};

Why array.join() doesn’t work

With JavaScript, the first tool that comes to mind for joining an array is the .join array method (obviously!). But it won't work here.

Because Array.join() only works with strings.

And my breadcrumb icon <BreadcrumbIcon /> isn't a string. It's a React component, and it returns JSX.

Let's see what happens when we try to use Array.join().

function Breadcrumb({ crumbs }) {
  return (
    crumbs.join(<BreadcrumbIcon />)
  );
};

// Home[object Object]Account[object Object]Settings

😬 [object Object]

Nope. Array.join() doesn't work with objects, and it certainly doesn't work with React components. If it's not a string, it's not going to work.

As an easy fix, I could change the divider to a string (e.g. ">") and get this to work. But looking ahead, while my crumbs are strings at the moment (for these examples), they probably won't be in the future. I'll use <Link> components - so that they are clickable for navigation.

And then I'll run into problems with Array.join() again.

How to join an array with a React component

Ok, let's figure out how to get this to work as we intended.

We want to:

  • Pass in an array (of strings or JSX) as a prop
  • Join the array items with a React component as the separator

I'm going to use my favourite Array method .map() to map over each item in the crumbs array, and as long as it's not the first item in the array, I will add the separator first (ourBreadcrumbIcon).

function Breadcrumb({ crumbs }) {
  return (
    crumbs.map((crumb, index) => (
        <React.Fragment key={index}>
            { !!index && <BreadcrumbIcon /> }
            { crumb }
        </React.Fragment>
    ))
  );
};

I'm using a <React.Fragment> here to avoid adding any additional markup (like a <div>), but if you want to add styles or classes, or want a wrapper for your breadcrumb for other reasons, you can swap out the <React.Fragment> for a <div> or other element.

If you are wondering why !!index && and not index && - using !! turns index into a boolean so 0 changes to false. If I used index && instead, I'd get a 0 showing up before the first breadcrumb item!

Now when you use Breadcrumb with any crumbs, of any length, the BreadcrumbIcon will display between each item.

<Breadcrumb crumbs={[ "Home", "Account", "Settings" ]} />

breadcrumb example with React separator

<Breadcrumb crumbs={[ "Home", "Super", "Cool", "With a cherry on top" ]} />

breadcrumb example 2 with React separator

How to join children

Maybe you are happy passing crumbs as a prop. I know I am pretty happy with it. But I mentioned that I might want to pass links or React components as my crumbs so that they are clickable and can be used for navigation.

Wouldn't it be cool if we could use the Breadcrumb component like this:

<Breadcrumb2>
  <a href="/home">Home</a>
  <a href="/account">Account</a>
  <a href="/account/settings">Settings</a>
</Breadcrumb2>

I'm using <a> elements for this example, but in a real React project, I would probably use React Routers <Link> component.

I think when I'm passing components or JSX to Breadcrumb, it looks nicer to pass them as children like in the example above. So let's see how we can make that work.

function Breadcrumb({ children }) {
  return (
    children.map((crumb, index) => (
        <React.Fragment key={index}>
            { !!index && <BreadcrumbIcon /> }
            { crumb }
        </React.Fragment>
    ))
  );
};

Well, that was easy! Just switch crumbs for children and we are good to go!

breadcrumb with links

And if you want either to work, you can do something like:

function Breadcrumb({ crumbs, children }) {
  return (
    (children || crumbs).map((crumb, index) => (
        <React.Fragment key={index}>
            { !!index && <BreadcrumbIcon /> }
            { crumb }
        </React.Fragment>
    ))
  );
};

Now you can pass the crumbs prop or give your crumbs as children to the component (with children taking priority).