0

I want to change class active in my local state on click and change inActive to all other objects in the state.

const [jobType, setJobType] = useState([
        {
            "class": "active",
            "type": "All Jobs"
        },
        {
            "class": "inActive",
            "type": "My Jobs"
        },
        {
            "class": "inActive",
            "type": "Saved Jobs"
        },
    ])

const jobTypeClick = (event, item) =>{
        alert("I am clicked")
        console.log(item)
        setJobType(...jobType, jobType.class:"active")
    }

const jobTypes = jobType.map((data) => {
        return (
            <p className={data.class+" mb-0 px-3 secondary-font fs-16"} key={data.type} onClick={event => jobTypeClick(event, data.type)}>{data.type}</p>
        )
    })
azbarcea
  • 3,323
  • 1
  • 20
  • 25
  • 1
    `jobType.class:"active"` looks like a syntax error – evolutionxbox Sep 24 '21 at 11:22
  • 1
    Duplicate: [React: how to update state.item\[1\] in state using setState?](https://stackoverflow.com/questions/29537299/react-how-to-update-state-item1-in-state-using-setstate) –  Sep 24 '21 at 11:23
  • Does this answer your question? [How to update state with usestate in an array of objects?](https://stackoverflow.com/questions/62918710/how-to-update-state-with-usestate-in-an-array-of-objects) – pilchard Sep 24 '21 at 11:25

2 Answers2

1

This solution will work, but keep in mind that type should be unique

const jobTypeClick = (event, item) => {
    setJobType(jobType.map(t => {
        return { ...t, "class": (t.type === item) ? "active" : "inActive" }
    }))
}

Otherwise, you can pass the element index to the function this assures you uniqueness within an Array. Another nice feature is to pass a callback to set. The callback will receive the latest value allowing you to use this function even within async logic.

const jobTypeClick = (event, index) => {
    setJobType(current => current.map((t, ix) => ({ ...t, "class": (ix === index) ? "active" : "inActive" }));
}
Newbie
  • 4,462
  • 11
  • 23
  • 2
    Don't just dump code. Explain what you've changed and why you've made that change. – Andy Sep 24 '21 at 11:29
  • Too fast, I was still editing ;) – Newbie Sep 24 '21 at 11:33
  • You don't have to be first to post. Next time take time to write a decent considered answer. – Andy Sep 24 '21 at 11:34
  • Thanks, this works perfectly for me, just a newbie question from my side. Why do we've to map? can't we just setState using the previous state clone and change value? – Muhammad Azfar Aslam Sep 24 '21 at 11:41
  • Yes, but you need to make a deep copy (copy the array but also the elements) to prevent altering elements present in the previous state. Map is used as we want a new array and we are creating a new object too (see the spread operation { ... t } – Newbie Sep 24 '21 at 12:38
  • @MuhammadAzfarAslam If you believe this answers your question please mark the answer as correct ;) – Newbie Sep 24 '21 at 12:39
  • Thanks for the explanation, I already marked it correct. Unfortunately, my vote doesn't count due to my account reputation. – Muhammad Azfar Aslam Sep 24 '21 at 14:04
-1

What you are doing in setJobType is Wrong setJobType(...jobType, jobType.class:"active")
To setJobType you need to pass an array with updated value

You need to loop all the jobTyes and make class "inActive" to all objects and make the one with same click index to "active"

You can use the below code I have added a third argument to read the index from click element and looping all jobTypes and make the correct one to active and other to inActive

const [jobType, setJobType] = useState([
        {
            "class": "active",
            "type": "All Jobs"
        },
        {
            "class": "inActive",
            "type": "My Jobs"
        },
        {
            "class": "inActive",
            "type": "Saved Jobs"
        },
    ])

const jobTypeClick = (event, item, i ) =>{
        alert("I am clicked")
        console.log(item)
        let prevJobType = [...jobType];
        prevJobType.map((d,index) => {...d, class: index == i ? "active" : "inActive")
        setJobType(prevJobType)
    }

const jobTypes = jobType.map((data, i) => {
        return (
            <p className={data.class+" mb-0 px-3 secondary-font fs-16"} key={data.type} onClick={event => jobTypeClick(event, data.type, i)}>{data.type}</p>
        )
    })
sojin
  • 2,158
  • 1
  • 10
  • 18
  • 1
    Don't just dump code. Explain what you've changed and why you've made that change. – Andy Sep 24 '21 at 11:29
  • 1
    The following line of code `prevJobType.map(d => d.class = "inActive")` is changing the state in-place, as the `prevJobType` is only a shallow copy – Nick Parsons Sep 24 '21 at 11:34
  • I have added teh description, thanks @Andy – sojin Sep 24 '21 at 11:35
  • prevJobType is already a copy. – sojin Sep 24 '21 at 11:36
  • @sojin Using `[...jobType]` only makes it a shallow copy, so the objects within `jobType` aren't copied which means they're still pointing to the same object references that the original state was, so you'll end up modifying the original state when you do. `d.class = "inActive"`, as `d` is referring to an object from the original state as it isn't a copy – Nick Parsons Sep 24 '21 at 11:39
  • OK thanks. will update my answer, – sojin Sep 24 '21 at 11:40
  • Updated it in answer, Thankyou – sojin Sep 24 '21 at 11:42