Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamically mapping an array of objects to table row

I'm trying to map an array of objects to table rows in React. I've tried countless suggestions on this site but nothing seems to render in the end.

I'm getting the array data from the db on componentWillMount as so:

         componentWillMount(){
         db.collection("games")
         .onSnapshot(function(querySnapshot){
             querySnapshot.forEach(function(doc){
                 games.push(doc.data())
             });
             console.log(games);
         })
      }

The data is loading properly as seen in games. games is declared as a global variable outside the react class.

So far I've tried mapping over the array like this:

renderRow = () => {
    games.map(function(val, i){
        return(
            <tr>
                <td key={i}>
                    {val.name}
                </td>
            </tr>
        )
    })
}

And then rendering it in the table like so:

            <table className="ui inverted table">
                <thead>
                    <tr>
                        <th>Lobby name</th>
                        <th>Players</th>
                        <th>Mode</th>
                        <th>Difficulty</th>
                        <th>Status</th>
                    </tr>
                </thead>
                <tbody>
                   {this.renderRow()}
                </tbody>
            </table>

But nothing seems to render. I'm not sure if i'm not mapping over it properly, or perhaps it's rendering the table values before the array is loaded with data. Any thoughts on this?

Edit: console.log(games) gives this:

(10) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]
0:
currentPlayers: 1
difficulty: ""
gameMode: "family"
host: "###########"
name: "Testing new reset"
players:
player: "###########"
__proto__: Object
timestamp: 1550704627051
__proto__: Object
1: {currentPlayers: 1, difficulty: "heroic", gameMode: "experienced", host: "", name: "Testtest", …}
2: {currentPlayers: 1, difficulty: "veteren", gameMode: "experienced", host: "", name: "Flashpoint experts only!", …}
like image 551
sags95 Avatar asked Feb 21 '19 18:02

sags95


2 Answers

You are not returning anything in renderRow so need to add return before games.map

Change

   renderRow = () => {
        games.map(function(val, i){
            return(
               <tr>
                  <td key={i}>
                      {val.name}
                  </td>
               </tr>
            )
        })
   }

To

  renderRow = () => {
        return games.map(function(val, i){
            return(
               <tr>
                  <td key={i}>
                      {val.name}
                  </td>
               </tr>
            )
        })
   }
like image 162
Hemadri Dasari Avatar answered Sep 21 '22 00:09

Hemadri Dasari


If the function you are calling in componentWillMount to fetch the games is asynchronous it may be that your React component renders before your data is fetched.

You should try to set the state of the component when the games array is fetched and the React will re-render the component.

eg.

class Games extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      games: []
    }
  }

  componentWillMount() {
    db.collection("games")
      .onSnapshot(function (querySnapshot) {
        let gamesArray = []
        querySnapshot.forEach(function (doc) {
          gamesArray.push(doc.data())
        });
        this.setState({ games: gamesArray })
      })
  }

  renderRow = () => {
    return this.state.games.map(function (val, i) {
      return (
        <tr>
          <td key={i}>
            {val.name}
          </td>
        </tr>
      )
    })
  }

  render() {
    return (
      <table className="ui inverted table">
        <thead>
          <tr>
            <th>Lobby name</th>
            <th>Players</th>
            <th>Mode</th>
            <th>Difficulty</th>
            <th>Status</th>
          </tr>
        </thead>
        <tbody>
          {this.renderRow()}
        </tbody>
      </table>
    )
  }
}
like image 41
Lazar Avatar answered Sep 20 '22 00:09

Lazar