1

I am trying to map a card component with user data which I get from the jsonplaceholder using axios. However, when I tried, it returns with "TypeError: Cannot read properties of undefined (reading 'map')". I tried all the solutions on the web without success. Please help!

Here is the code that declared 'users';

export const useAllUsers = () => {
  const [users, setUsers] = useState<Array<User>>()
  const getUsers = useCallback(() => {
    axios
      .get<Array<User>>('https://jsonplaceholder.typicode.com/users')
      .then(res => {
        setUsers(res.data)})
         .catch(() => {
           return <MessageError />
         })
         .finally(()=>{
           setLoading(false)
         })
  }, [])
  return { getUsers, loading, users }
}

Then, I tried to map the 'users' get the all the user data as below:

export const UserManagement: VFC = memo(() => {
  const { getUsers, users, loading } = useAllUsers()
  useEffect(() => getUsers(), [])

  return (
    <>
      {loading ? (
        <div className=' flex justify-center items-center'>
          <div className='animate-spin rounded-full h-32 w-32 border-b-2 border-gray-900'></div>
        </div>
      ) : (
        <div
          className='grid 
        grid-cols-2 mb-16 md:grid-cols-3 lg:grid-cols-4 sm:px-6 md:px-16'
        > 
           <div className='grid mx-auto'> 
            {users.map(user => (
              <UserCard
                key={user.id}
                userName={user.username}
                imageUrl='https://source.unsplash.com/random'
                userId={user.name}
              />
            ))}
          </div> 
        </div> 
       )} 
    </>
  )
})

User type is just having a bunch of types for user data, so I think this is not the problem, I guess?

export type User = {
  id: number
  name: string
  username: string
  email: string
  hobbies: string
}
Chi
  • 276
  • 1
  • 8
  • 20
  • 2
    Change to this: `const [users, setUsers] = useState>([])` so the initial state is an empty array rather than undefined. – Jared Smith Sep 20 '21 at 23:06
  • 2
    Ohhh It worked! Thank you so much! – Chi Sep 20 '21 at 23:12
  • Duplicate: [Error : Cannot read property 'map' of undefined](https://stackoverflow.com/questions/24706267/error-cannot-read-property-map-of-undefined) –  Sep 20 '21 at 23:12

2 Answers2

3

I think your trying to map your users before the get request is done so it's undefined. Try something like

{
  users &&
    users.map((user) => (
      <UserCard
        key={user.id}
        userName={user.username}
        imageUrl="https://source.unsplash.com/random"
        userId={user.name}
      />
    ));
}
Thomas
  • 177
  • 1
  • 7
  • To add to this, it can be helpful to make the initial state of an Array type state to be an empty array. This means you can skip the `users &&`, as users will now never be undefined, the `map` will just see no items to map out. Once the data is loaded, the component will re-render with the new `users` array and map out your data. – LevPewPew Sep 20 '21 at 23:10
  • Please check for dupes before posting an answer. This is a *very* common beginner's mistake that is posted all the time. –  Sep 20 '21 at 23:14
  • dude you saved me hours !!!! thank you – Jackie Santana Mar 26 '22 at 01:47
1

You have a loading "state" to guard against attempting to render the items before any data has been fetched, but in useAllUsers you never actually declared the loading with a useState, so in the UserManagement it will always be false, leading it to attempt to render users before they are ready.

To fix, you can add the missing loading useState, and I also advise to put an empty array as the initial value of an array type state like so:

const [users, setUsers] = useState<Array<User>>([])
LevPewPew
  • 159
  • 7
  • Please check for dupes before posting an answer. This is a *very* common beginner's mistake that is posted all the time. –  Sep 20 '21 at 23:14