简体   繁体   中英

React renders an empty array item on mount, how can I avoid that?

I'm once again here asking for help, I have this component that renders an empty array item on mount, how can I avoid that and conditionally render a <p> tag that tells the user there's no items in the array yet? I have tried this code but it didn't work. This is my component (I know I have to refactor it, I just want to make it work first):

import React, { useState, useEffect } from "react"
const formatThousands = require("format-thousands")

const Clients = () => {
  const [client, setClient] = useState({})
  const [allClients, setAllClients] = useState([])
  const [name, setName] = useState("")
  const [cuota, setCuota] = useState("")
  const [id, setId] = useState("")

  useEffect(() => {
    setAllClients([...allClients, client])
  }, [client])

  function handleSubmit(event) {
    event.preventDefault()
    if (!name || !cuota || !id) return
    setClient({ ...client, name, cuota, id })
    setName("")
    setCuota("")
    setId("")
  }
  function handleDeleteButton(id) {
    allClients.filter(cl => id !== cl.id)
  }
  return (
    <div className="container">
      <form className="input-group" onSubmit={handleSubmit}>
        <span className="input-group-text">Nuevo cliente</span>
        <input
          type="text"
          className="form-control"
          placeholder="Agregar un nuevo cliente"
          value={name}
          onChange={event => setName(event.target.value)}
        />
        <input
          type="number"
          placeholder="Monto cuota"
          className="form-control"
          value={cuota}
          onChange={event => setCuota(event.target.value)}
        />
        <input
          type="number"
          placeholder="identificador"
          className="form-control"
          value={id}
          onChange={event => setId(event.target.value)}
        />
        <button className="btn btn-success" type="submit">
          Agregar
        </button>
      </form>
      <div className="text-center my-2">
        <h3>Clientes</h3>
      </div>
      <table className="table table-striped">
        <thead>
          <tr>
            <th scope="col">Cliente</th>
            <th scope="col">Cuota</th>
            <th scope="col">Identificador</th>
          </tr>
        </thead>
        <tbody>
          {allClients ? (
            allClients.map(client => (
              <tr key={client.id}>
                <td>{client.name}</td>
                <td>{formatThousands(client.cuota)}</td>
                <td>{client.id}</td>
                <td>
                  <button
                    onClick={() => handleDeleteButton(client.id)}
                    className="btn btn-danger btn-sm"
                  >
                    Borrar
                  </button>
                </td>
              </tr>
            ))
          ) : (
            <p>Sin clientes</p>
          )}
        </tbody>
      </table>
    </div>
  )
}

export default Clients

This is the output I get on mount:

在此处输入图像描述

This is the initial value of allClients, I don't know why Array [ {} ]

This is your current code:

allClients ? allClients.map : <p></p> 

In contrast, this is what your code should be:

allClients.length ? allClients.map : <p></p> 

allClients is an empty array so it returns true. Instead, your code should check allClients.length which actually returns the length of the array.

This is caused by the useEffect block. You add and empty object to the array the first time the component is rendered. That is why this condition allClients.length > 0 is true:

This is the initial value of allClients, I don't know why Array [ {} ]

Solution 1: Initialize allClients with null . Do the same with client. Check if client has value:

const [client, setClient] = useState(null)
const [allClients, setAllClients] = useState(null);

useEffect(() => {
   if(client) setAllClients([...allClients || [], client]);
}, [client]);

Solution 2: Initialize only client with null and then check for allClients.length > 0 to render the elements.

const [client, setClient] = useState(null)
const [allClients, setAllClients] = useState([]);

useEffect(() => {
   if(client) setAllClients([...allClients, client]);
}, [client]);

In both case you will need to check if client has a valid value.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM