Learn why passing plain objects directly into JSX crashes your React app and how to fix it cleanly.

At‑a‑Glance Fix

Convert any plain object into a renderable value before placing it in JSX, typically by:

  1. Accessing a specific primitive (e.g., user.name).
  2. Serialising the whole object (e.g., JSON.stringify(user)).
  3. Mapping an array of objects to an array of React elements.

Why This Error Happens

React’s renderer accepts strings, numbers, React nodes, and arrays/fragments of nodes. A bare object has no visual representation, so React throws:

Error: Objects are not valid as a React child (found: object with keys {…})

This usually happens when data from an API, state, or props is passed straight into JSX without being broken down first.

Prerequisites

  • React 16+ (hooks available)
  • Working knowledge of JS objects, arrays, and data fetching
  • Optional: TypeScript for stronger type safety

Step‑by‑Step Guide

Follow these hands-on steps to identify, fix, and prevent this common rendering mistake in React.

Step 1: Spot the Offending Code

function UserProfile({ user }: { user: object }) {

  return (

    <div>

      {/* ❌ Passing entire object – will crash */}

      {user}

    </div>

  );

}

Step 2: Render Primitive Fields or Serialise

function UserProfile({ user }: { user: User }) {

  return (

    <div>

      {/* ✅ Render individual fields */}

      <p>Name: {user.name}</p>

      <p>Email: {user.email}</p>

      {/* ✅ Or serialise for debugging */}

      <pre>{JSON.stringify(user, null, 2)}</pre>

    </div>

  );}

Step 3: Handle Arrays the React Way

type User = { id: number; name: string };

const UserList: React.FC<{ users: User[] }> = ({ users }) => (

  <ul>

    {users.map(({ id, name }) => (

      <li key={id}>{name}</li> // ✅ render primitive

    ))}

  </ul>

);

Step 4: Full Working Demo

import React from “react”;

// Mock data

action const demoUser = {

  id: 1,

  name: “Alice Johnson”,

  email: “[email protected]”,

  age: 30,

  address: {

    street: “123 React Lane”,

    city: “Devville”,

    zip: “90210”,

  },

};

function UserCard({ user }: { user: typeof demoUser }) {

  if (!user) return <p>No user data.</p>;

 

  return (

    <article style={{ border: “1px solid #ccc”, padding: 16, borderRadius: 8 }}>

      <h2>{user.name}</h2>

      <p>Email: {user.email}</p>

      <p>Age: {user.age}</p>

      <p>

        Address: {user.address.street}, {user.address.city}, {user.address.zip}

      </p>

 

      {/* Debug view – formatted JSON */}

      <pre style={{ background: “#f7f7f7”, padding: 12 }}>

        {JSON.stringify(user, null, 2)}

      </pre>

    </article>

  );

}

 

export default function App() {

  return (

    <main style={{ fontFamily: “sans‑serif”, textAlign: “center” }}>

      <h1>React Child Error Demo</h1>

      <UserCard user={demoUser} />

      {/* Incorrect usage (commented to avoid crash) */}

      {/* <div>{demoUser}</div> */}

    </main>

  );}

Highlights:

  • Shows both correct and incorrect patterns.
  • Inline styling avoids external CSS to keep the example self‑contained.

Also Read: Top React Best Practices for Scalable Frontends

Common Pitfalls & How to Fix Them

Pitfall Example Safe Fix
Rendering entire API response <div>{apiData}</div> <div>{apiData.title}</div> or JSON.stringify(apiData)
Forgetting to map array {users} where users is [{},{}] {users.map(u => <UserCard key={u.id} user={u} />)}
Directly rendering Date <span>{new Date()}</span> <span>{new Date().toISOString()}</span>

Conclusion

Remember:

  • Never drop a raw object in JSX.
  • Extract the primitives you need or serialise the data for display.
  • Use mapping or formatting helpers to keep components clean, readable, and error‑free.