UseState Object - Card Components

Hi there!
I have built a very simple card using useState Object, that contains: a profile picture, name, last name, and a few more information.

I replicate the code but any changes on the second card have not been applied as you can see from the screenshot.

My question is:
Is correct to use useState Object for multiple cards or better to use Props?

I am still not sure if in this scenario it could be better to use state and Props.

Thank you for the help.
P.

1 Like

Using useState for something like that is fine. The issue is going to be how you are changing it. If you are mutating the internals without creating a new reference, React may not know that it has changed so it may not know to rerender.

You can post the code where you are changing the state - please post the code, not a picture.

I would also google “react change array of objects no mutation”. This is an important topic that trips up a lot of learners.

1 Like

Thank you for the explanation. here is the code:

import React from 'react'
import { useState } from 'react'

export default function CardStateObject() {
    const [contact, setContact]= useState(
    {
        id: 1,
        firstName: "Marc",
        lastName: "Lee",
        phone: "333 199 2233",
        email: "hello@lee.com",
        isFavorite: true,
        isOnline: false
    }
    )
    

    let starIcon = contact.isFavorite ? "star-filled.png" : "star-empty.png"
    let activeStatus = contact.isOnline ? "Online" : "OffLine"

  return (
    <div>
        <article>
            <img src="./user.png" />
        </article>
        <div>
            <img src={`./${starIcon}`} className="star--icon"/>
            <p>{`${activeStatus}`}</p>
            <h2>{contact.firstName} {contact.lastName}</h2>
                <p>{contact.phone}</p>
                <p>{contact.email}</p>
        </div>
        
    </div>
  )
}

I don’t understand. You said “any changes on the second card have not been applied”. Where are you making changes?

Are you just saying that both rendered cards are the same? I don’t even see where you were rendering two cards. For that matter, in your original clip, the data structure is wrong - if there are more than one contact, the variable should be renamed, and those two would have to be wrapped in an object or more likely an array. But now it’s different in the second code so I don’t know what you are trying to do.

If you want more than one, then it should be “contacts” and it should be an array of objects, and you’re probably going to have to “map” over them.

Hi @Plee & @kevinSmith,

The issue is how useState hook (not Object) was used in the first place. Instead of receiving one argument as the initial value to be set as the contact, @Plee provided 2 arguments, as 2 separate objects.

I haven’t looked into internals of useState, but I believe that second argument gets dismissed and the result could be explained that @Plee is calling CardStateObject (sorry, but that’s a terrible name) multiple times elsewhere hoping to see different results, when in reality this component has a hard-coded state to represent Marc.

P.S. I really don’t think this component should have any state inside of it, because it’s not going to change. What you probably want to do, is:

  1. Create an array of contacts
  2. Map over elements of array and return a ContactCard component with contact values passed through props

Edit: Hopefully my response isn’t offending. Let me know if you need more help with this one :pray:

2 Likes

Yes, I believe so. That’s why I was supposing that he was wanting an array of contacts.

CardStateObject (sorry, but that’s a terrible name)

Yeah, I was debating whether or not to say something. I agree. It’s not an object, it’s not a state. If it’s for displaying a contact, I’d call it “Contact” or “ContactCard”.

I really don’t think this component should have any state inside of it, because it’s not going to change.

That’s a good point.

  1. Create an array of contacts
  2. Map over elements of array and return a ContactCard component with contact values passed through props

Yeah, I’d agree with that. The array of contacts should probably be in the parent component (or some ancestor).

1 Like

Thanks for the explanation. If I understood is not the ideal situation to use useState…

you need to loop bro:

<div>
{contact.map(({firstName, lastName,email,email)=> {
(
    <div>
        <article>
            <img src="./user.png" />
        </article>
        <div>
            <img src={`./${starIcon}`} className="star--icon"/>
            <p>{`${activeStatus}`}</p>
            <h2>{firstName} {lastName}</h2>
                <p>{phone}</p>
                <p>{email}</p>
        </div>
        
    </div>
  )
})
}
</div>

If I understood is not the ideal situation to use useState…

No, we’re saying that it should be state in a different place, lifted up, to a parent element. You need state somewhere, so the app can keep track. The point is that it shouldn’t be in each contact but in a master contacts list. If my app had this structure:

App --
     |
     -- Settings
     |
     -- Login
     |
     -- Contacts --
                   |
                   |
                   -- Contact

Then I would expect the contact information state to not be in Contact, but to be in Contacts or maybe App, and passed down. (Alternatively there are things like context and redux, but let’s stick to the basics.) Then, as @vebradev mentioned, in Contacts you are going to have an array contacts. With that, somewhere in your Contacts JSX you are going to have something like contacts.map(Contact) or contacts.map(({ /* ... */ }) => <Contact /* ... */ />).

But you need state. Whether that is in a class component (going out of style) or in a functional component with useState or whatever - you need state. useState is a good way to do that and I think a good way to start.

2 Likes

All clear now. I need to study an practise now.