For the code I am currently working on, I have a very complicated array filled with objects. The point of this page is to change one property of one object in the array at a time, and as is such, the entire array needs to be updated to carry out that change. The array is initialized as so...
const [allDevices, setAllDevices] = useState(initialDeviceNames)
where intialDeviceNames will either be a populated object fetched from a query, or an empty array if there is no matching instance. That will look like this...
note that an empty object (if none with a matching date value is found) will have every number property set to {id: null, name: "No Driver Selected"}
0:
0: {id: 'dfebc7ce-ea4b-48d4-9fd9-7c2d02572e40', name: 'DANIEL STITT', type: 'Vehicle'}
1: {id: '64303dc1-0ba6-43bb-a25a-9885f9e8f2e3', name: 'KENNETH WILLIFORD', type: 'Vehicle'}
2: {id: '1a778957-b679-401b-972d-aeb32f84e667', name: 'JASON PITSNOGLE', type: 'Vehicle'}
3: {id: '1fcc9d60-fc6f-4e34-b5ab-c64d5ea8778a', name: 'VIRGINIA SHADE', type: 'Vehicle'}
4: {id: null, name: 'No Driver Assigned'}
5: {id: null, name: 'No Driver Assigned'}
6: {id: null, name: 'No Driver Assigned'}
amount: 6
name: "Vehicle"
remaining_drivers: (60) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]
[[Prototype]]: Object
1:
0: {id: '1a778957-b679-401b-972d-aeb32f84e667', name: 'JASON PITSNOGLE', type: 'iPad'}
1: {id: 'dfebc7ce-ea4b-48d4-9fd9-7c2d02572e40', name: 'DANIEL STITT', type: 'iPad'}
2: {id: '1fcc9d60-fc6f-4e34-b5ab-c64d5ea8778a', name: 'VIRGINIA SHADE', type: 'iPad'}
3: {id: '203726da-dba7-4f74-9d86-919d6a02a282', name: 'DONNA HAGGERTY', type: 'iPad'}
4: {id: null, name: 'No Driver Assigned'}
5: {id: null, name: 'No Driver Assigned'}
6: {id: null, name: 'No Driver Assigned'}
7: {id: null, name: 'No Driver Assigned'}
8: {id: null, name: 'No Driver Assigned'}
9: {id: null, name: 'No Driver Assigned'}
10: {id: null, name: 'No Driver Assigned'}
amount: 10
name: "iPad"
remaining_drivers: (60) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]
[[Prototype]]: Object
So updating this one at a time is clearly complicated. I have to find the right object in the array, then find the right number property inside that object, change it, and then get the whole state to update. The code I had for this worked until I added some pre-population functionality. The code for updating any of these single properties will be shown below...
const handleDriverSelection = (driver, index, superIndex, deviceObj) => {
// If driver is the same
if (allDevices[superIndex][index].name == `${driver.firstname} ${driver.lastname}`){
}
// If active driver is empty
else if (allDevices[superIndex][index].name == "No Driver Assigned" || allDevices[superIndex][index] == 'undefined'){
console.log(allDevices)
let newArray = [...allDevices]
// The specific device drop selected will be set equal the the driver clicked
newArray[superIndex][index] = {
name: `${driver.firstname} ${driver.lastname}`,
id: driver.id,
type: deviceObj.name
}
// This removes the driver from the list of remaining driver
newArray[superIndex].remaining_drivers = newArray[superIndex].remaining_drivers.filter( (remDriver) => {
if (driver != remDriver){
return remDriver
}
})
// This sets the state
setAllDevices(newArray)
}
// if active driver exists but is NOT the one inputted
else if (allDevices[superIndex][index].name != "No Driver Assigned" ){
console.log(allDevices)
let newArray = [...allDevices]
// This finds the driver that was previously selected and adds him/her back to the remaining list
// For each driver...
user.drivers.forEach( (dspDriver) => {
// if the driver iterated == the driver that was previously selected
if (allDevices[superIndex][index].name == `${dspDriver.firstname} ${dspDriver.lastname}`){
// Adds the driver to remaining drivers
newArray[superIndex].remaining_drivers = [...newArray[superIndex].remaining_drivers, dspDriver]
// Sets the current drop state to the driver selected
newArray[superIndex][index] = {
name: `${driver.firstname} ${driver.lastname}`,
id: driver.id,
type: deviceObj.name
}
// Removes the driver selected from the list of remaining drivers
newArray[superIndex].remaining_drivers = newArray[superIndex].remaining_drivers.filter( (remDriver, index) => {
if (driver != remDriver){
return remDriver
}
})
setAllDevices(newArray)
}
})
}
}
This is where I'm getting very confused-- through the line
let newArray = [...allDevices]
I would think that newArray creates an array with the exact same contents of allDevices. allDevices, since it is a local state, is read-only. I understand this. I also understand that had I wrote let newArray = allDevices that newArray would also be read only since it would not be a new array but rather just a different variable pointing to the value of allDevices.
As is such, I have no idea why this ISNT working, since newArray shouldn't be read-only at all. The code I added had a multitude of complicated useEffects to handle querying, mutating and refreshing, so I can't see how it would effect the code I showed above, especially since newArray doesn't exist anywhere but this code.