almeynman
almeynman

Reputation: 7398

Invariant Violation: Objects are not valid as a React child

In my component's render function I have:

render() {
    const items = ['EN', 'IT', 'FR', 'GR', 'RU'].map((item) => {
      return (<li onClick={this.onItemClick.bind(this, item)} key={item}>{item}</li>);
    });
    return (
      <div>
        ...
                <ul>
                  {items}
                </ul>
         ...
      </div>
    );
  }

everything renders fine, however when clicking the <li> element I receive the following error:

Uncaught Error: Invariant Violation: Objects are not valid as a React child (found: object with keys {dispatchConfig, dispatchMarker, nativeEvent, target, currentTarget, type, eventPhase, bubbles, cancelable, timeStamp, defaultPrevented, isTrusted, view, detail, screenX, screenY, clientX, clientY, ctrlKey, shiftKey, altKey, metaKey, getModifierState, button, buttons, relatedTarget, pageX, pageY, isDefaultPrevented, isPropagationStopped, _dispatchListeners, _dispatchIDs}). If you meant to render a collection of children, use an array instead or wrap the object using createFragment(object) from the React add-ons. Check the render method of Welcome.

If I change to this.onItemClick.bind(this, item) to (e) => onItemClick(e, item) inside the map function everything works as expected.

If someone could explain what I am doing wrong and explain why do I get this error, would be great

UPDATE 1:
onItemClick function is as follows and removing this.setState results in error disappearing.

onItemClick(e, item) {
    this.setState({
      lang: item,
    });
}

But I cannot remove this line as I need to update state of this component

Upvotes: 527

Views: 958583

Answers (30)

Dogbert
Dogbert

Reputation: 222040

I just got the same error but due to a different mistake: I used double braces like:

{{count}}

to insert the value of count instead of the correct:

{count}

which the compiler turned into {{count: count}}, i.e. trying to insert an Object as a React child.

Upvotes: 63

user2675933
user2675933

Reputation: 1

So I had an array with JSX elements [h1, h3, div, null, div] properly declared for instance <h1 key={someh1key}>content</h1> on that list etc. I go to render it in a form:

const myform = (<form onSubmit={formik.handleSubmit}>{mytds}
            <button type="submit">Submit</button>
            <button type="button" onClick={(event) => history.push("/")}>Cancel</button>
        </form>);

and got the error: Uncaught Error: Objects are not valid as a React child (found: object with keys {mytds}). If you meant to render a collection of children, use an array instead.

There are some solutions to this problem:

  1. for me it was: wrap the list in a Fragment because a Fragment lets you render multiple elements, of different types, so a fragment was what I needed around the list. <>{mytds}</>.

  2. Sometimes, your array just has data, but no JSX elements. In that case you will also see this error. You can avoid it by using something like: array.map((item, index) => <div key={index}>{item}</div>); will work and get rid of the error, though React recommends using unique keys and only using the index as a last resort.

Above works because it will produce an array of React JSX Elements all of the same type with unique keys.

Now the form looks like this:

const myform = (<form onSubmit={formik.handleSubmit}><>{mytds}</>
            <button type="submit">Submit</button>
            <button type="button" onClick={(event) => history.push("/")}>Cancel</button>
        </form>);

I came across this: Objects are not valid as a React child. If you meant to render a collection of children, use an array instead so this might be a duplicate question.

This was also helpful, but still did not answer the question. https://kinsta.com/knowledgebase/objects-are-not-valid-as-a-react-child/#:~:text=Another%20common%20cause%20of%20the,a%20valid%20React%20child%20element.

Upvotes: 0

PalPalash
PalPalash

Reputation: 142

This was my code :

class App extends Component {
  constructor(props){
    super(props)
    this.state = {
      value: null,
      getDatacall : null
    }
    this.getData = this.getData.bind(this)
  }
  getData() {
  //   if (this.state.getDatacall === false) {
    sleep(4000)
    returnData("what is the time").then(value => this.setState({value, getDatacall:true}))
    // }
  }
  componentDidMount() {
    sleep(4000)

    this.getData()
  }
  render() {
    this.getData()
    sleep(4000)
    console.log(this.state.value)
    return (
      <p> { this.state.value } </p>
    )
  }
}

when I ran into the error in question. I had to change it to :

 render() {
    this.getData()
    sleep(4000)
    console.log(this.state.value)
    return (
      <p> { JSON.stringify(this.state.value) } </p>
    )
  }

Upvotes: 6

Andy
Andy

Reputation: 156

I got this "not valid as a React child" error because I passed an object as a prop from a parent component, and then I tried to render a property of that object as a string, when it was actually a Date. Rendering that as a string instead removed this error.

Upvotes: 0

Hikmatullah Faizan
Hikmatullah Faizan

Reputation: 11

I think this problem mostly happens because of forgetting curly braces, which leads that JavaScript doesn't realize all elements as an array. In my case, it was like this:

function DynamicRow(id, name, avatar, email, salary, date, status){

and the solution:

function DynamicRow({id, name, avatar, email, salary, date, status}){

Upvotes: 1

Renjith P N
Renjith P N

Reputation: 4231

This can happen when you try to render objects as child elements, you can find out the root cause by looking for below scenarios.

  1. Check if you are using any double braces in JSX - <span>{{value}}</span> and change it to <span>{value}</span> (I did this mistake since I just moved from Angular to React).

  2. Check of return statements wrapped around braces like below and remove it.

     render() {
       let element = (
        <span>text</span>
       );
    
       return (
        {element}  // => Remove this extra brace
       )
     }
    
  3. Check any other unintentional way you are using object in the JSX

     let nestedObjected = {
        a : '1',
        b : {
           c: '2'
        }
     };
     {Object.keys(nestedObjected).map((key) => {
        return (
            <div>
               <span>{nestedObjected[key]}</span>  // This will cause issue since it will resolve to an object
            </div>
        );
      })}
    

Upvotes: 2

Bennington
Bennington

Reputation: 308

If you have placed 'async' in front of a functional component (either a wrapper for a jest & react-testing-library test or just a plain old functional component) like this:

const MockComponent = async () => {
  <Provider>
    <ComponentImGoingToTest />
  </Provider>
}

And you're expecting to be able to render it like this:

<MockComponent />

then two things:

  1. You don't understand the implications of what async does.
  2. Because of that keyword, calling your wrapper function will invoke a promise (which is an object), instead of the expected React functions that JSX boils down to.

Upvotes: 1

Roy Ng
Roy Ng

Reputation: 23

As I experienced same, besides adding "__html" to mark it, I resolved by putting marked HTML into a span with attribute "dangerouslySetInnerHTML" like below:

  createMarkup(innerHtml){
    return {__html: innerHtml};
  }

  render = () => {
    return (
      <span dangerouslySetInnerHTML={
      this.createMarkup(this.props.details.entryContent)}/>
    );
  }

Upvotes: 0

Dishant Dishu
Dishant Dishu

Reputation: 81

If you are printing Object/ Arrays in the console.log then also this error comes. Make sure you add JSON. stringify if you want to do console.log for objects/Arrays

Upvotes: 1

Ricardo alvarez
Ricardo alvarez

Reputation: 31

Well, I spent half day trying to solve this

I wanted to show an array depending on if a user was logged in

this is what my code looked like return ({ userLogged ? userLoggedCart : cartItems } .map((item)=>{ return //irrelevant code})) but this was wrong, if your code looks like this you got to change it to

if (userLogged){ return ( userLoggedCart.map((item)=>{ return //your code }))} else { cartItems.map((item)=>{ return // your code })}

Upvotes: 0

thelonglqd
thelonglqd

Reputation: 1862

My case is quite common when using reduce but it was not shared here so I posted it.

Normally, if your array looks like this:

[{ value: 1}, {value: 2}]

And you want to render the sum of value in this array. JSX code looks like this

<div>{array.reduce((acc, curr) => acc.value + curr.value)}</div>

The problem happens when your array has only one item, eg: [{value: 1}]. (Typically, this happens when your array is the response from server so you can not guarantee numbers of items in that array)

The reduce function returns the element itself when array has only one element, in this case it is {value: 1} (an object), it causes the Invariant Violation: Objects are not valid as a React child error.

Upvotes: 3

Revan99
Revan99

Reputation: 446

the problem is that when you render the li you are passing not passing the function to the component you are calling it so it will call it once the li is rendered for that you need to pass the reference to the function not calling it to do that you ether write it like this if there was no argument to pass

onClick={this.onItemClick.bind}

or like this if there were arguments to pass

onClick={()=>this.onItemClick.bind(this, item)}

in this case it will create an anonymous function an pass it's reference

Upvotes: 0

ali orooji
ali orooji

Reputation: 41

Due to the error, react considered you are trying to display the object of 'li', but you really don't.

You used 'bind' method in the wrong place. When you use bind in the 'li', 'this' will be considered the object of 'li'. Since object has an extra keyword(onItemClick), henceforth it's not a react tag, and it's a js object with the properties those react li tag, has.

If you use the 'bind' method in constructor of Component there will be no problem. But in your usecase this is impossible. So the "(e) => onItemClick(e, item)" is the best try.

Ignore my bad English.

Upvotes: 0

Haris
Haris

Reputation: 61

Just remove the async keyword in the component.

const Register = () => {

No issues after this.

Upvotes: 4

Namig Hajiyev
Namig Hajiyev

Reputation: 1531

Just remove the curly braces in the return statement.

Before:

render() {
    var rows = this.props.products.map(product => <tr key={product.id}><td>{product.name}</td><td>{product.price}</td></tr>);
    return {rows}; // unnecessary
}

After:

render() {
    var rows = this.props.products.map(product => <tr key={product.id}><td>{product.name}</td><td>{product.price}</td></tr>);
    return rows; // add this
}

Upvotes: 6

cormacncheese
cormacncheese

Reputation: 1729

I got this error any time I was calling async on a renderItem function in my FlatList.

I had to create a new function to set my Firestore collection to my state before calling said state data inside my FlatList.

Upvotes: 3

DutchPrince
DutchPrince

Reputation: 363

Try this

 {items && items.title ? items.title : 'No item'}

Upvotes: 0

Meet Zaveri
Meet Zaveri

Reputation: 3059

React child(singular) should be type of primitive data type not object or it could be JSX tag(which is not in our case). Use Proptypes package in development to make sure validation happens.

Just a quick code snippet(JSX) comparision to represent you with idea :

  1. Error : With object being passed into child

    <div>
    {/* item is object with user's name and its other details on it */}
     {items.map((item, index) => {
      return <div key={index}>
    --item object invalid as react child--->>>{item}</div>;
     })}
    </div>
    
  2. Without error : With object's property(which should be primitive, i.e. a string value or integer value) being passed into child.

    <div>
     {/* item is object with user's name and its other details on it */}
      {items.map((item, index) => {
       return <div key={index}>
    --note the name property is primitive--->{item.name}</div>;
      })}
    </div>
    

TLDR; (From the source below) : Make sure all of the items you're rendering in JSX are primitives and not objects when using React. This error usually happens because a function involved in dispatching an event has been given an unexpected object type (i.e passing an object when you should be passing a string) or part of the JSX in your component is not referencing a primitive (i.e. this.props vs this.props.name).

Source - codingbismuth.com

Upvotes: 30

corysimmons
corysimmons

Reputation: 7675

Typically this pops up because you don't destructure properly. Take this code for example:

const Button = text => <button>{text}</button>

const SomeForm = () => (
  <Button text="Save" />
)

We're declaring it with the = text => param. But really, React is expecting this to be an all-encompassing props object.

So we should really be doing something like this:

const Button = props => <button>{props.text}</button>

const SomeForm = () => (
  <Button text="Save" />
)

Notice the difference? The props param here could be named anything (props is just the convention that matches the nomenclature), React is just expecting an object with keys and vals.

With object destructuring you can do, and will frequently see, something like this:

const Button = ({ text }) => <button>{text}</button>

const SomeForm = () => (
  <Button text="Save" />
)

...which works.

Chances are, anyone stumbling upon this just accidentally declared their component's props param without destructuring.

Upvotes: 8

tolga
tolga

Reputation: 2800

In my case, I added a async to my child function component and encountered this error. Don't use async with child component.

Upvotes: 3

Shubham Patil
Shubham Patil

Reputation: 51

I got the same error, I changed this

export default withAlert(Alerts)

to this

export default withAlert()(Alerts).

In older versions the former code was ok , but in later versions it throws an error. So use the later code to avoid the errror.

Upvotes: 5

Suresh Mangs
Suresh Mangs

Reputation: 725

I had the same problem because I didn't put the props in the curly braces.

export default function Hero(children, hero ) {
    return (
        <header className={hero}>
            {children}
        </header>
    );
}

So if your code is similar to the above one then you will get this error. To resolve this just put curly braces around the props.

export default function Hero({ children, hero }) {
    return (
        <header className={hero}>
            {children}
        </header>
    );
}

Upvotes: 5

Yuvraj Patil
Yuvraj Patil

Reputation: 8726

In my case it was because of a dynamic array which had to be injected at runtime.

I just added the null checks for object and it worked fine.

Before:

...
render(
...
    <div> {props.data.roles[0]} </div>
...
);

After:

...
let items = (props && props.data && props.data.roles)? props.data.roles: [];
render(
...
    <div> {items[i]} </div>
...
);

Upvotes: 1

Arul
Arul

Reputation: 1179

Found: object with keys

Which means you passing something is a key-value. So you need to modify your handler:

from
onItemClick(e, item) {
   this.setState({
     lang: item,
   });
}
to
onItemClick({e, item}) {
  this.setState({
    lang: item,
  });
}

You missed out the braces ({}).

Upvotes: 1

Ken A Collins
Ken A Collins

Reputation: 291

I too was getting this "Objects are not valid as a React child" error and for me the cause was due to calling an asynchronous function in my JSX. See below.

class App extends React.Component {
    showHello = async () => {
        const response = await someAPI.get("/api/endpoint");

        // Even with response ignored in JSX below, this JSX is not immediately returned, 
        // causing "Objects are not valid as a React child" error.
        return (<div>Hello!</div>);
    }

    render() {
        return (
            <div>
                {this.showHello()}
            </div>
        );
    }
}

What I learned is that asynchronous rendering is not supported in React. The React team is working on a solution as documented here.

Upvotes: 18

Tanaka
Tanaka

Reputation: 354

For those who mentioned Stringify() and toString() as solution, I will say that worked for me but we have to understand the problem and why did it occur. In my code it was simple issue. I had 2 buttons which call same function but one button was not passing the argument to that function properly.

Upvotes: 0

Acy
Acy

Reputation: 659

I got this error rendering something in a ternary operator. What I did:

render(){
  const bar = <div>asdfasdf</div>
  return ({this.state.foo ? {bar} : <div>blahblah</div>})
}

Turns out it should be bar without the brackets, like:

render(){
  const bar = <div>asdfasdf</div>
  return ({this.state.foo ? bar : <div>blahblah</div>})
}

Upvotes: 0

Matthis Kohli
Matthis Kohli

Reputation: 1995

Just create a valid JSX element. In my case I assigned a component to an object.

const AwesomeButtonComponent = () => <button>AwesomeButton</button>
const next = {
  link: "http://awesomeLink.com",
  text: "Awesome text",
  comp: AwesomeButtonComponent
}

Somewhere else in my Code I wanted to dynamically assign that button.

return (
  <div>
    {next.comp ? next.comp : <DefaultAwesomeButtonComp/>}
  </div>
)

I solve this by declaring a JSX comp which I initialized via the props comp.

const AwesomeBtnFromProps = next.comp
return (
  <div>
    {next.comp ? <AwesomeBtnFromProps/> : <DefaultAwesomeButtonComp/>}
  </div>
)

Upvotes: 0

Philip Wrage
Philip Wrage

Reputation: 1559

Obviously, as others have mentioned previously in this thread, in React JSX props.children cannot be of type Object. This is NOT the root cause for the issue in your specific question.

If you carefully read the error text, you will see that React has produced the error while trying to render an Object that matches the signature of a SyntheticEvent:

Uncaught Error: Invariant Violation: Objects are not valid as a React child (found: object with keys {dispatchConfig, dispatchMarker, nativeEvent, target, currentTarget, type, eventPhase, bubbles, cancelable, timeStamp, defaultPrevented, isTrusted, view, detail, screenX, screenY, clientX, clientY, ctrlKey, shiftKey, altKey, metaKey, getModifierState, button, buttons, relatedTarget, pageX, pageY, isDefaultPrevented, isPropagationStopped, _dispatchListeners, _dispatchIDs}). If you meant to render a collection of children, use an array instead or wrap the object using createFragment(object) from the React add-ons. Check the render method of Welcome.

However, one wonders why you are trying to render a SyntheticEvent, and this is where the real answer to your question resides. You obviously have no intention of rendering a SyntheticEvent, but you've got your event handler parameters out of order.

In your render method, you are binding the onItemClick event handler to the this of your class component and passing in item as an argument:

render() {
    const items = ['EN', 'IT', 'FR', 'GR', 'RU'].map((item) => {
      return (<li onClick={this.onItemClick.bind(this, item)} key={item}>{item}</li>);
    });
// ...

According to the documentation for Function.prototype.bind, all arguments passed after the thisArg are prepended to any arguments subsequently passed when the target function is later invoked:

arg1, arg2, ...

Arguments to prepend to arguments provided to the bound function when invoking the target function.

If we then look at the event handler, we see that the parameter e is listed before the parameter item.

onItemClick(e, item) {
    this.setState({
      lang: item,
    });
}

When onItemClick(e, item) is invoked, the item passed in during the bind invocation will precede the triggering event, so parameter e will be set to the mapped and bound item, and parameter item will be set to the event.

When setState is called, lang will be set to the SyntheticEvent representing the triggering onClick event, and when you try to render the value in this.state.lang elsewhere, you will receive the Invariant Violation error you've seen.

Upvotes: 0

Lucas Bustamante
Lucas Bustamante

Reputation: 17168

If you are using Firebase and seeing this error, it's worth to check if you're importing it right. As of version 5.0.4 you have to import it like this:

import firebase from '@firebase/app'
import '@firebase/auth';
import '@firebase/database';
import '@firebase/storage';

Yes, I know. I lost 45 minutes on this, too.

Upvotes: 2

Related Questions