Organize table with reactjs and firebase

Asked

Viewed 77 times

1

I am receiving data from Firebase with Reactjs and my problem is that I want to organize this data in the table as follows:

inserir a descrição da imagem aqui

But I can’t do it, that’s the result I got:

inserir a descrição da imagem aqui

I know it is a relatively simple problem and would be grateful if someone could help. Below is my code.

function Exemplo() {
  const [users, setUsers] = React.useState([])

  React.useEffect(() => {
    // const db = firebase.firestore()
    // db.collection('equipes').onSnapshot(data => {
    //  setUsers(data.docs.map(doc => ({ ...doc.data() })))
    // })
    // Esses são os dados mapeados do firebase:
    setUsers([
     {
        "name": "Furia",
        "players": [
           { "name": "Eduardo", "attack": 18, "defense": 2 },
           { "name": "Tiago", "attack": 15, "defense": 3 },
           { "name": "Julia", "attack": 10, "defense": 0 }
        ]
     },
     {
        "name": "Incriveis",
        "players": [
           { "name": "Eduardo", "attack": 11, "defense": 4 },
           { "name": "Tiago", "attack": 17, "defense": 0 },
           { "name": "13", "attack": 13, "defense": 6 }
        ]
     }
    ]);
  }, [])

  if (users) {
    return (
      <div>
        <table>
          <thead>
            <tr>
              <th rowSpan="2">#</th>
              <th rowSpan="2">Nome</th>
              <th colSpan="2">Furia</th>
              <th colSpan="2">Incriveis</th>
            </tr>

            <tr>
              <td>Ataques</td>
              <td>Defesas</td>
              <td>Ataques</td>
              <td>Defesas</td>
            </tr>
          </thead>
          <tbody>
            {users.map((user, index) => (
              <React.Fragment key={index}>
                {user.players.map((u, index) => (
                  <tr key={index}>
                    <td>{index + 1}</td>
                    <td>{u.name}</td>
                    <td>{u.attack}</td>
                    <td>{u.defense}</td>
                  </tr>
                ))}
              </React.Fragment>
            ))}
          </tbody>
        </table>
      </div>
    )
  }
}

ReactDOM.render(<Exemplo />, document.querySelector("#container"));
<div id="container"></div>
<script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>

  • Instead of sharing a Firebase print, it’s easier to share what your array users possesses as value. What it seems to me is that the person is repeated in user.players, would need to make a .reduce if that’s right.

  • Thanks for the touch. But it’s really repeated. The idea is for the team to be associated with players like the first image of the table I showed. I structured in the firestore in that way as an example, because I had no better idea.

  • All right, buddy, I added

  • The answer solved your problem, Bruno?

  • Actually the data will be dynamic using a form to add. I put only 2 teams and 3 sample players. About the database the structure I put was to have an idea. But your answer is helping me to have some ideas. If I can solve the problem or have any questions back with the feedback. Thank you!

1 answer

0

The problem is that the data format is not the same format you want to display. There are a few ways to solve, but I think the easiest/readable way is to have the array ready to be mapped to the table, where each element of the array represents a row.

Let’s say our goal is to have the following array:

[
  {
    "name":"Eduardo",
    "furia":{
      "attack":18,
      "defense":2
    },
    "incriveis":{
      "attack":11,
      "defense":4
    }
  },
  {
    "name":"Tiago",
    "furia":{
      "attack":15,
      "defense":3
    },
    "incriveis":{
      "attack":17,
      "defense":0
    }
  },
  {
    "name":"Julia",
    "furia":{
      "attack":10,
      "defense":0
    },
    "incriveis":{
      "attack":13,
      "defense":6
    }
  }
]

We can achieve this goal with the function .map, see the code inside the useEffect:

function Exemplo() {
  const [users, setUsers] = React.useState([])

  React.useEffect(() => {
    const data = [
     {
        "name": "Furia",
        "players": [
           { "name": "Eduardo", "attack": 18, "defense": 2 },
           { "name": "Tiago", "attack": 15, "defense": 3 },
           { "name": "Julia", "attack": 10, "defense": 0 }
        ]
     },
     {
        "name": "Incriveis",
        "players": [
           { "name": "Eduardo", "attack": 11, "defense": 4 },
           { "name": "Tiago", "attack": 17, "defense": 0 },
           { "name": "Julia", "attack": 13, "defense": 6 }
        ]
     }
    ];

    // data[0] representa "Furia", data[1] representa "Incriveis"
    const parsedUsers = data[0].players.map(player => {
      // Considerando que o jogador seja único por "name", procuramos ele no
      // array de "Incriveis" para pegar seu "attack" e "defense"
      const incriveisStatus = data[1].players.find(
        incriveisPlayer => incriveisPlayer.name === player.name
      );

      return {
        name: player.name,
        furia: {
          attack: player.attack,
          defense: player.defense
        },
        incriveis: {
          attack: incriveisStatus.attack,
          defense: incriveisStatus.defense
        }
      }
    });
    
    setUsers(parsedUsers);
  }, [])

  if (users) {
    return (
      <div>
        <table>
          <thead>
            <tr>
              <th rowSpan="2">#</th>
              <th rowSpan="2">Nome</th>
              <th colSpan="2">Furia</th>
              <th colSpan="2">Incriveis</th>
            </tr>

            <tr>
              <td>Ataques</td>
              <td>Defesas</td>
              <td>Ataques</td>
              <td>Defesas</td>
            </tr>
          </thead>
          <tbody>
            {users.map((user, index) => (
              <tr key={user.name}>
                <td>{index + 1}</td>
                <td>{user.name}</td>
                <td>{user.furia.attack}</td>
                <td>{user.furia.defense}</td>
                <td>{user.incriveis.attack}</td>
                <td>{user.incriveis.defense}</td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    )
  }
}

ReactDOM.render(<Exemplo />, document.querySelector("#container"));
<div id="container"></div>
<script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>

Remarks:

  1. I had settled it with reduce, but it became too complex just to be something more "dynamic", and this would not bring benefit because the table is not dynamic (it has only Furia and Incriveis).
  2. I changed the key to the name of user because index is not good to serve as key, and name is the only value that seems to be used as unique in your data. If you have a id, change the key to the id and also in the .find to look for id.

This is probably not the ideal solution, but for a small amount of data and for only two "types" (Furia and Incriveis), works well. If you want something dynamic, you can try making a reduce, but remember that you will have to leave the table with dynamic columns as well. It can be a good exercise to practice.

It’s complicated because the data array is not in a good format, maybe changing the database is a good idea, but it takes context to understand how it could be and I have no experience with unstructured databases to opine here.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.