Home > OS >  How to handle Error: Objects are not valid as React child?
How to handle Error: Objects are not valid as React child?

Time:10-31

I have an array of objects that displays the name property. I succeeded with the mapping and then with ordering the list of names in alphabetical order. Then I tried adding a search bar and filter/search by entering an input but got this error that I don't know how to solve as I got a bit confused with the nested methods and the parenthesis. (A newbie here!)

Can someone spot what's wrong? Not sure if the second part of my code is needed but added it anyway. Sorry it gets too long.

Unhandled Rejection (Error): Objects are not valid as a React child (found: object with keys {id, name, username, email, address, phone, website, company}). If you meant to render a collection of children, use an array instead.

const UserList = () => {
 
  const [users, setUsers] = useState([])
  const [selectedUser, setSelectedUser] = useState()
  const [showUser, setShowUser] = useState(true)
  const [search, setNewSearch] = useState("")
  
  const onHandleClick = () => setShowUser(false)
  
  const DisplayUser =(user) => {
    setSelectedUser(user)
    setShowUser(true)
  }
  
  const handleSearchChange = (e) => {
    setNewSearch(e.target.value)
  }

  useEffect(() => {
    fetch(URL)
      .then(res => res.json())
      .then(json => setUsers(json));
  }, [])

  return (
    <>
      <Header>      
        <h1>Contact list</h1>
      </Header>
      <input type="text" value={search} onChange={handleSearchChange}  />
      <Container> 
          <div>
          {!search 
            ?  users.sort((a,b) => a.name.localeCompare(b.name)) 
            :  users.filter(user => user.name.toLowerCase().includes(search.toLowerCase()))
          .map(user => (
            <div key={user.id}>
              <User onClick ={() => DisplayUser(user)}>{user.name}</User>
            </div>
          ))}      
          </div> 

SECOND PART:

 {selectedUser && (
          <>
            {showUser ?
            <UserDetail 
              name={selectedUser.name} 
              username={selectedUser.username}
              email={selectedUser.email}
              address={selectedUser.address.street}
              address2={selectedUser.address.suite}
              city={selectedUser.address.city}
              phone={selectedUser.phone}
              website={selectedUser.website}
              company={selectedUser.company.name}
              onClick={onHandleClick}
            />
            : false}           
          </>
        )}       
      </Container>    
    </>
  )
}

CodePudding user response:

It's a bit hard for me to tell for sure, but I think what's probably happening is the following:

{!search 
            ?  users.sort((a,b) => a.name.localeCompare(b.name)) 
            :  users.filter(user => user.name.toLowerCase().includes(search.toLowerCase()))
          .map(user => (
            <div key={user.id}>
              <User onClick ={() => DisplayUser(user)}>{user.name}</User>
            </div>
          ))}  

If search is false, this will return users.sort((a,b) => a.name.localeCompare(b.name)), which is an object, when you meant to apply the .map to the result of the entire ternary operation. Right now .map is only attached to the users.filter(...) piece.

I expect parentheses around the "sort or filter", will work, since then it will map in either case, not just the "else" case.

{(!search 
            ?  users.sort((a,b) => a.name.localeCompare(b.name)) 
            :  users.filter(user => user.name.toLowerCase().includes(search.toLowerCase())))
          .map(user => (
            <div key={user.id}>
              <User onClick ={() => DisplayUser(user)}>{user.name}</User>
            </div>
          ))}  

Since code like this can be hard to follow, I highly recommend extracting logic like this into a function, say, getUser(), so you could do something like this instead:

{getUsers().map(user => (
            <div key={user.id}>
              <User onClick ={() => DisplayUser(user)}>{user.name}</User>
            </div>
          ))}  
  • Related