0

I am trying to send an array of objects that I get from MongoDB to client(React.js) using Node.js. However, I keep running into Objects are not valid as a React child (found: object with keys {_id, desc, price, purchased}) error, while I am sure I have passed the data in correct format.

What the array looks like:

[{
          desc:"Manage",
          price: 5000,
          purchased: false,
        },
        {
          desc:"Deliver",
          price: 2000,
          purchased: false,
        },
        {
          desc:"Market",
          price: 4000,
          purchased: false,
        },
        {
          desc:"Agentone",
          price: 8000,
          purchased: false,
        },
        {
          desc:"CPM",
          price: 14000,
          purchased: false,
        },
        {
          desc:"Data",
          price: 17000,
          purchased: false,
        },
        {
          desc:"E-Sign",
          price: 9000,
          purchased: false,
        },
        {
          desc:"IGO",
          price: 3000,
          purchased: false,
        },
        {
          desc:"DocFast",
          price: 7000,
          purchased: false,
        }
      ],

My server side:

app.get('/item_info', (req, res) => {
  var data;
  MongoClient.connect(url, { useNewUrlParser: true }, function(err, db) {
    if (err) throw err;
    var dbo = db.db("ItemList");
    dbo.collection("ItemInfo").find().toArray(function(err, result) {
      if (err) throw err;
      res.send({express: result})
      db.close();
    });
  });
});

My client:

constructor(props){
  super(props)
  this.state={
     itemList:[]
  }
}




componentDidMount() {
        this.callApi()
          .then(res => this.setState({itemList: res.express}))
          .catch(err => console.log(err));

      console.log(this.state.data)
  }

  callApi = async () => {
      const response = await fetch('/item_info');
      const body = await response.json();
      if (response.status !== 200) throw Error(body.message);

      return body;
  };

  render()  {
    return (
      <div>
        <div className="App">
          <header className="App-header">
            <img src={logo} className="App-logo" alt="logo" />
            <h1 className="App-title">Welcome to Reactr</h1>
          </header>
        </div>
        <div>{this.state.itemList[0]}</div>
     </div>
    )}

In order to confirm that the client is getting the right format, I print the res.express to console and it shows the following:

(9) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]
0: {_id: "5bb223f5b717bc0aa0f5cf92", desc: "Manage", price: 5000, purchased: false}
1: {_id: "5bb223f5b717bc0aa0f5cf93", desc: "Deliver", price: 2000, purchased: false}
2: {_id: "5bb223f5b717bc0aa0f5cf94", desc: "Market", price: 4000, purchased: false}
3: {_id: "5bb223f5b717bc0aa0f5cf95", desc: "Agentone", price: 8000, purchased: false}
4: {_id: "5bb223f5b717bc0aa0f5cf96", desc: "CPM", price: 14000, purchased: false}
5: {_id: "5bb223f5b717bc0aa0f5cf97", desc: "Data", price: 17000, purchased: false}
6: {_id: "5bb223f5b717bc0aa0f5cf98", desc: "E-Sign", price: 9000, purchased: false}
7: {_id: "5bb223f5b717bc0aa0f5cf99", desc: "IGO", price: 3000, purchased: false}
8: {_id: "5bb223f5b717bc0aa0f5cf9a", desc: "DocFast", price: 7000, purchased: false}
length: 9
__proto__: Array(0)

So the client is getting the correct format of array. I can't figure out why react is yelling at me

3
  • Can you show how react is "yelling" at you? Commented Oct 1, 2018 at 15:51
  • @MattKuhns I am getting an error where it says :Objects are not valid as a React child (found: object with keys {_id, desc, price, purchased} Commented Oct 1, 2018 at 16:34
  • @MattKuhns also, when I try to access it by doing {this.state.itemList[0].desc}, it says Cannot read property 0 of null, so the the client does not receive the data properly Commented Oct 1, 2018 at 16:35

1 Answer 1

1

You are trying to render an object directly. As you can see by looking the error you get, it is not possible to do that. So, you need to render this object's properties.

render() {
  return (
    <div>
      <div className="App">
        <header className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <h1 className="App-title">Welcome to Reactr</h1>
        </header>
      </div>
      <p>{this.state.itemList[0].desc}</p>
      <p>{this.state.itemList[0].price}</p>
      // and so on
    </div>
  );
}

Of course, you don't want to render all the objects manually. So, first use .map method on your array then render the properties.

class App extends React.Component {
  state = {
    itemList: [
      {
        _id: "1",
        desc: "Manage",
        price: 5000,
        purchased: false
      },
      {
        _id: "2",
        desc: "Deliver",
        price: 2000,
        purchased: false
      },
      {
        _id: "3",
        desc: "Market",
        price: 4000,
        purchased: false
      }
    ]
  };

  renderItems() {
    return this.state.itemList.map(item => (
      <div key={item._id}>
        <p>Desc: {item.desc}</p>
        <p>Price: {item.price}</p>
        {!item.purchased ? <p>Not purchased</p> : <p>Purchased</p>}
      </div>
    ));
  }

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

ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>

Sign up to request clarification or add additional context in comments.

8 Comments

this.state.itemList[0] returns error Cannot read property '0' of null, so the real problem is the setstate where itemList does not properly gets the data
And my problem is that if I do console.log(res.express), I actually see the data, however, the setstate is just not getting it
@SpencerOvetsky, this is because your data is coming from an async operation. In the first render there is no itemList[0], so you can't get a property from undefined. Have you tried my code? Like mapping, then render the items? You can see one single property like this: { this.state.itemList[0] && this.state.itemList[0].desc } But again, most of the time you want to map your data then render it somehow. You can also do conditional rendering again.
I did. It worked. Is there a work around besides using map? Since I need to use these data in child component and modify individual child component separately(different styling). Does using axios work?
At some point, you have to use .map. Having a child component does not affect this, instead of rendering directly just pass the item to the child component and do there whatever you want. axios or any other fetch method is not related to your issue. Your data is coming after the first render so you should do conditional rendering if you have an issue about this.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.