3
votes

I have a React project set up to fetch an Object from a Firebase database and render this to my page. However I do not know how to render the data properly.

The data I am fetching looks like this:

{
    "projects": {
        "0": {
            "title": "test",
            "function": "test2"
        },
        "1": {
            "title": "test3",
            "function": "test4"
        }
    }
}

In the Chrome React Debugger I see this:

<div>
    <Message key="0" data={function: "test2", title: "test", key: "0"}>...</Message>
    <Message key="1" data={function: "test4", title: "test3", key: "1"}>...</Message>
</div>

But in the elements view I am simply seeing two empty divs:

<div>
    <div></div> == $0
    <div></div>
</div>

Currently I am passing <Message key={index} data={message} /> to a Message component containing {this.props.message}

EDIT: Changed this to {this.props.data} since no message prop was passed to Message component

Refactoring the code to: <div> key={index} data={message} </div> however returns the error

Objects are not valid as a React child (found: object with keys {function, title, key}). 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 ProjectList.

Seeing as the project items have keys I do not believe CreateFragment is the correct solution. Also Firebase favors passing objects with keys over arrays so the solutions I am given does not seem to work in this situation. But how can I then control how the objects are rendered on the page?

My complete ProjectList component looks like this:

import React from 'react';
import firebase from 'firebase';
import _ from 'lodash';
import Message from './Message'

class ProjectList extends React.Component {
  constructor(props){
    super(props);
    this.state = {
      messages: {}
    };

    this.firebaseRef = firebase.database().ref('projects');
    this.firebaseRef.on("child_added", (msg)=> {
      if(this.state.messages[msg.key]){
        return;
      }

      let msgVal = msg.val();
      msgVal.key = msg.key;
      this.state.messages[msgVal.key] = msgVal;
      this.setState({messages: this.state.messages});
    });
  }

   render(){
    var messageNodes = _.values(this.state.messages).map((message, index)=> {
      return (
        <Message key={index} data={message} />
      );
    });

    return (
      <div>
          {messageNodes}
      </div>
    );
  }
}

export default ProjectList;

Thanks!

Edit: changed the Message component render to {this.props.data} as Message component receives no message prop.

3
What does the Message component render?Blorgbeard
All I have in Message is:constructor(props){ super(props); } render(){ return ( <div> {this.props.message} </div> ) }dwigt
@dwigt Message is not receiving any message prop. Please add this snippet to the questionmartriay

3 Answers

3
votes

Change your Message render method to:

render() {
  return <div>{this.props.data}</div>
}
0
votes

You are passing the prop to the message component by name data and rendering it using this.props.message which is wrong.

Use this.props.data.

export default class Message extends React.Component {

constructor(props){ 
    super(props); 
} 
render(){ 
    return ( 
       <div> {this.props.data} </div> 
    ) 
 }

}
0
votes

Regarding the error `Objects are not valid as a React child (found: object with keys {function, title, key}). I changed my prop from an object to an array. Finally I changed my message component to this.props.data since no message prop was passed as the other posters have noted.

The array fix:

class ProjectList extends React.Component {
  constructor(props){
    super(props);
    this.state = {
      messages: []
    };

Thank you so much for the help!