4 Comments

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.