React報錯之Objects are not valid as a React child

2022-08-05 06:00:33

正文從這開始~

總覽

當我們嘗試在JSX程式碼中,直接渲染物件或者陣列時,會產生"Objects are not valid as a React child"錯誤。為了解決該錯誤,在JSX程式碼中,使用map()方法來渲染陣列或者存取物件的屬性。

下面是錯誤如何發生的範例。

export default function App() {
  const employees = [
    {id: 1, name: 'Alice', country: 'Austria'},
    {id: 2, name: 'Bob', country: 'Belgium'},
    {id: 3, name: 'Carl', country: 'Canada'},
  ];

  const obj = {
    id: 4,
    name: 'Dean',
    country: 'Denmark',
  };

  // ⛔️ Uncaught Error: Objects are not valid as a React child (found: object with keys {id, name, country}).
  // If you meant to render a collection of children, use an array instead.

  return (
    <div>
      {employees}

      {obj}
    </div>
  );
}

map

上述程式碼片段的問題在於,在JSX程式碼中我們嘗試直接渲染陣列或者物件。

為了解決該錯誤,當渲染JSX程式碼時,使用map()方法來渲染陣列或者存取物件的屬性。

export default function App() {
  const employees = [
    {id: 1, name: 'Alice', country: 'Austria'},
    {id: 2, name: 'Bob', country: 'Belgium'},
    {id: 3, name: 'Carl', country: 'Canada'},
  ];

  const obj = {
    id: 4,
    name: 'Dean',
    country: 'Denmark',
  };

  return (
    <div>
      {employees.map((employee, index) => {
        return (
          <div key={index}>
            <h2>name: {employee.name}</h2>
            <h2>country: {employee.country}</h2>

            <hr />
          </div>
        );
      })}

      <hr />
      <hr />
      <hr />

      <div>
        <h2>name: {obj.name}</h2>
        <h2>county: {obj.country}</h2>
      </div>

      <hr />
    </div>
  );
}

當偵錯時,可以使用console.log來列印導致錯誤的值。

JSON.stringify

或者,你可以在JSX程式碼中使用JSON.stringify()轉換該值,以確保它是預期的型別。

export default function App() {
  const employees = [
    {id: 1, name: 'Alice', country: 'Austria'},
    {id: 2, name: 'Bob', country: 'Belgium'},
    {id: 3, name: 'Carl', country: 'Canada'},
  ];

  const obj = {
    id: 4,
    name: 'Dean',
    country: 'Denmark',
  };

  return (
    <div>
      <h4>{JSON.stringify(employees)}</h4>

      <h4>{JSON.stringify(obj)}</h4>
    </div>
  );
}

JSON.stringify()方法將會在物件渲染之前,將其轉換為字串。

你必須確保在JSX程式碼中,不會渲染物件或者陣列。相反,你必須渲染原始值,比如說字串以及數值。

Date

另一個導致該錯誤的常見原因是,在JSX程式碼中我們試圖直接渲染Date物件時。

export default function App() {
  const date = new Date();

  // ⛔️ Objects are not valid as a React child (found: [object Date]).
  return (
    <div>
      <h4>{date}</h4>
    </div>
  );
}

為了解決該問題,我們必須存取Date物件上的方法,比如說,toLocaleDateString()

export default function App() {
  return (
    <div>
      <h4>{date.toLocaleDateString()}</h4>
    </div>
  );
}

現在,我們使用字串代替物件來進行渲染,因此該錯誤被解決。

花括號

如果錯誤依舊存在,請確保當渲染變數時,你沒有使用雙花括號。

export default function App() {
  const message = 'hello world';

  // ⛔ Objects are not valid as a React child (found: object with keys {message}).
  return (
    <div>
      <h4>{{message}}</h4>
    </div>
  );
}

注意message變數包裹在兩組花括號內,這也是為什麼React認為嘗試渲染一個物件。為了解決該問題,可以只將變數包裹在一組大括號中。

export default function App() {
  return (
    <div>
      <h4>{message}</h4>
    </div>
  );
}

現在React把message變數當作一個包含字串的表示式,而不是一個物件。

async

如果錯誤依舊存在,請確保在JSX程式碼中沒有呼叫async函數。

async函數返回一個Promise物件,因此在JSX程式碼中,如果呼叫了async函數,則錯誤就會發生。

export default function App() {
  async function getData() {
    return Promise.resolve(42);
  }

  // ⛔ Objects are not valid as a React child (found: [object Promise]).
  return (
    <div>
      <h4>{getData()}</h4>
    </div>
  );
}

為了解決該錯誤,我們必須在useEffect勾點或者事件處理器裡呼叫async函數,比如說,onClick

import {useEffect, useState} from 'react';

export default function App() {
  const [num, setNum] = useState(0);

  useEffect(() => {
    async function getData() {
      const result = await Promise.resolve(42);

      setNum(result);
    }

    getData();
  }, []);

  return (
    <div>
      <h4>{num}</h4>
    </div>
  );
}

useEffect勾點中呼叫async函數可以解決這個錯誤,因為我們現在渲染的是一個數位,而不是Promise物件。

總結

發生"Objects are not valid as a React child"的React錯誤有多種原因:

  • 在JSX程式碼中直接渲染物件或者陣列;
  • 在JSX程式碼中直接渲染Date物件;
  • 在兩組花括號中包裹變數,比如:{{message}}而不是{message}
  • 在JSX程式碼中呼叫async函數。