Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Text nodes cannot appear as a child of <table> [ReactJS]

Why am I receiving this warning?

Warning: validateDOMNesting(...): Text nodes cannot appear as a child of <table>.

In some cases I saw that it is about some white spaces, but I don't see how this applies in here.

My code:

        return (
            <div className="container">
                <div>
                    <h2 style={{color: 'red'}}>Lista de Clientes</h2>
                </div>
                <br/>

                <table className="table table-bordered">
                    <thead className="thead-dark">
                        <tr>
                            <th>#</th>
                            <th>Nome</th>
                            <th>Telefone</th>
                            <th>E-mail</th>
                            <th>Detalhar</th>
                            <th>Excluir</th>
                        </tr>
                    </thead>
                    { inserirClientes }
                </table>
            </div>
        );

In here the loop that creates inserirClientes

        let inserirClientes = this.state.mensagem

        if (this.state.retorno) {

            inserirClientes = (
                Object.keys(this.state.clientes)
                    .map((key, i) =>
                                <tbody key={key + i}  >
                                    <Clientes 
                                        remover={this.removerClienteHandler} 
                                        clienteInfo={this.state.clientes[key]} 
                                        clickRemove={() => this.fetchHandler()}
                                        indice={i}
                                    />
                                </tbody>
                        )
            )
        }

EDIT:

I started generating <tr> in the loop instead of <tbody> and the error persists, but now I am getting this:

Warning: validateDOMNesting(...): Text nodes cannot appear as a child of <tbody>

let inserirClientes = this.state.mensagem

    if (this.state.retorno) {

        inserirClientes = (
            Object.keys(this.state.clientes)
                .map((key, i) => (
                            <tr key={`${key}${i}`}  >
                                <Clientes 
                                    remover={this.removerClienteHandler} 
                                    clienteInfo={this.state.clientes[key]} 
                                    clickRemove={() => this.fetchHandler()}
                                    indice={i}
                                />
                            </tr>
                    ))
        )
        console.log(inserirClientes)
    }

    return (
        <div className="container">
            <div>
                <h2 style={{color: 'red'}}>Lista de Clientes</h2>
                <h4 style={{color: 'red'}}>OBS.: Verificar se é a melhor maneira de se criar tal tabela. Talvez seja possível criar um componente para isso</h4>
            </div>
            <br/>

            <table className="table table-bordered">
                <thead className="thead-dark">
                    <tr>
                        <th>#</th>
                        <th>Nome</th>
                        <th>Telefone</th>
                        <th>E-mail</th>
                        <th>Detalhar</th>
                        <th>Excluir</th>
                    </tr>
                </thead>
                <tbody>{inserirClientes}</tbody>
            </table>
        </div>
    );

Any idea how to solve this?

like image 238
Berg_Durden Avatar asked Jan 29 '26 20:01

Berg_Durden


1 Answers

The answer lies with the initial value of inserirClientes.

Since you've initialized inserirClientes to be equal to this.state.mensagem, this component's first render will use that as the initial value, because Object.keys(this.state.clientes).map() has not yet had a chance to run.

I'm guessing these are your initial state values?

state = {
  mensagem: 'initial message',
  retorno: false,

  // other values...
}

If so, inserirClientes has the value of 'initial message' on first render, and you're effectively doing this:

<tbody>{'initial message'}</tbody>


Solution

Since you'd probably like to show the initial message before the data has loaded, we can simply provide the necessary markup around the initial message to make it valid inside <table>.

// since this will be a child of <tbody>, start with valid <tr> markup
let inserirClientes = <tr><td>{this.state.mensagem}</td></tr>

// if data has returned, replace initial message with array of <tr>s
if (this.state.retorno) {
  inserirClientes =
    Object.keys(this.state.clientes).map((key, i) => (
      <tr key={`${key}${i}`}  >
        <Clientes 
          remover={this.removerClienteHandler} 
          clienteInfo={this.state.clientes[key]} 
          clickRemove={() => this.fetchHandler()}
          indice={i}
        />
      </tr>
    ))
}

console.log(inserirClientes)

return (
  <div className="container">
    <div>
      <h2 style={{color: 'red'}}>Lista de Clientes</h2>
      <h4 style={{color: 'red'}}>OBS.: Verificar se é a melhor maneira de se criar tal tabela. Talvez seja possível criar um componente para isso</h4>
    </div>
    <br/>

    <table className="table table-bordered">
      <thead className="thead-dark">
        <tr>
          <th>#</th>
          <th>Nome</th>
          <th>Telefone</th>
          <th>E-mail</th>
          <th>Detalhar</th>
          <th>Excluir</th>
        </tr>
      </thead>
      <tbody>{inserirClientes}</tbody>
    </table>
  </div>
)
like image 150
simmer Avatar answered Jan 31 '26 09:01

simmer



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!