Resolving Error: “Objects are not valid as a React child”

When building a React component, I ran into this error:

Objects are not valid as a React child (found: object with keys...

Invariant Violation: Objects are not valid as a React child (found: object ...). If you meant to render a collection of children, use an array instead....

Here is a simple component to illustrate the problem.

import * as React from "react";
type Status =
  | "Open"
  | "Closed"

type PureProps = {
  status: Status;
};

function StatusDescription(status: Status): JSX.Element {
  return <span>{status}</span>;
}

export class StatusSummary extends React.PureComponent {
  render() {
    return (
      <StatusDescription status={this.props.status} />
    );
  }
}

Looking for the Problem

The issue appeared to be in the type of Status and how it was being rendered.

I tried a few different iterations, first rendering the string literal directly inside the component. My thinking was that the type Status may not be rendering correctly if TypeScript was mistaking it for an object. When I replaced the props with Status.Closed and saw the error disappear and the correct text render on the page, I was ensured that it was not an issue with the type definition of Status or the way it is rendered.

However, this does not solve the problem:

function StatusDescription: JSX.Element {
  return {Status.Closed}; // Error gone and component renders, but problem remains
}

Next, I replaced the type Status with string, but the error persisted. Passing in a string and continuing to see an error told me that the props themselves were incorrect, but perhaps not in the way that I was expecting.

function StatusDescription(status: string): JSX.Element {
  return {status}; // Error persists
}

Solution

In the end, the problem turned out to be not with the StatusDescription function, but rather with the props I was passing it.

Note that <StatusDescription status={status} /> is being used as a React component, which expects an object with the needed props. Here, TypeScript did not give any type errors, but instead interpreted status as an object. This caused problems later on when trying to render the string literal status in the `JSX.Element`.

The first change necessary was to define an object that contains the props the component needs.

function StatusDescription(props: {
  status: Status;
}): JSX.Element {
    return {props.status};
}

Now it is valid to use StatusDescription as a React component.

A similar approach, which I find easier to read, is to define the Props type separately.

type ComponentProps = {
  status: Status;
  // Whatever else is needed
}
function StatusDescription(props: ComponentProps): JSX.Element {
  return {props.status};
}

Lesson Learned

Seeing an Objects are not valid as a React child error might mean that a few different things are going wrong. For example, it could be because the items being rendered in the JSX Element are objects instead of primitives (so make sure you’re not passing an object where a primitive is expected).

In this case, however, I was reminded that React components always expect to take an object that contains the props it needs. I was burned by this because the component only needs one prop (a string), which I was trying to directly pass in. By making a simple change to the props type of the component, I was able to make the error disappear.

Conversation
  • MDeibert says:

    Sentence 2 in “Lesson Learned” solved my problem. Thank you!

  • Andrew says:

    I was hoping this article would also help solve mine, and so far I’m still trying to find which component might be causing the issue. Is there a way to see which component is breaking it?
    Everything seemed to be going fine, the app was running and then suddenly after a refresh it stopped working. I rolled back the changes, dropped it to last working commit and still getting the error.
    Any hints on troubleshooting the troubled component?

  • Evgheni Anachii says:

    Thank you! Good article!

    • Meredith Lind Meredith Lind says:

      Thank you for reading and finding it helpful!

  • Ryan says:

    Just a heads up, I noticed immediately that you were passing “status” into the `StatusDescription` component without destructuring it. If you are going to pass a prop into a functional component this way you need to destructure it. So doing the following would have also solved your issue. If you don’t destructure props being passed into the component the first argument is “props” or simply put the object that contains status.

    function StatusDescription({status}: Status): JSX.Element {
    return {status};;
    }

    • Meredith Lind Meredith Lind says:

      Hi Ryan,
      Thank you for reading this post! Destructuring props is another valid way of passing data down and could help with the issue here. Thanks for the input of a stylistically different approach!

  • Vocko says:

    Hi Meredith,
    thanks for the post, I got the same issue when changed api call and related infrastructure and my code was suddenly spitting a date object into the jsx instead of the previous date formatted string. The error message given wasn’t very helpful at the beginning, this helped me to track it down!

    Cheers,
    Vocko

    • Meredith Lind Meredith Lind says:

      Hi Vocko,
      Glad you found it helpful!

  • Sean Alloway says:

    Thank you – helped me resolve issue!

  • Comments are closed.