Reputation: 311
I have booksOwned
inside an array of objects, and I want to add another book to "John Doe"
's booksOwned.
const [ownerInfo, setOwnerInfo] = React.useState([
{
owner: "John Doe",
booksOwned: ["To Kill a Mockingbird", "1984"],
},
{
owner: "John Doe Jr",
booksOwned: [
"Harry Potter and the Philosopher's Stone",
"The Lord of the Rings",
],
},
])
This is what I've tried so far, does not seem to work.
let data = ownerInfo
let newBook = "Pride and Prejudice"
//to store currently owned books
let currBooks = []
//get the index of object I need
let ind = data.map((val, i) => {
if (val.owner === "John Doe") {
currBooks = val.booksOwned
return i
} else {
return -1
}
})
let bookIndex = currBooks.indexOf(newBook)
//insert only if book does not yet exist
if (bookIndex === -1) {
data[ind] = {
owner: "John Doe",
booksOwned: currBooks.push(newBook),
}
setOwnerInfo(data)
}
Upvotes: 0
Views: 90
Reputation: 364
A simple approach would be to use functional setState. Basically, setState can accept function as it's argument. Something like this:
const newBook = 'Pride and Prejudice'
// When using setOwnerInfo with functions as argument, it
// receives currentState as argument so we can use it.
// Use map to create a new array, instead of modifying it.
setOwnerInfo(owners => owners.map(owner => {
// First check for correct owner. Return if this is wrong one.
if (owner.onwer !== "John Doe") { return owner }
// Second, check that book doesn't exist already. Return if it does.
if (owner.booksOwned.find(ownedBook => ownedBook === newBook) !== undefined) { return owner }
// Book doesn't exist. Add it.
// Let's create a new object, instead of mutating it.
return {...owner, booksOwned: [...owner.booksOwner, newBook]}
}))
One thing about react state is that you shouldn't mutate it. It can lead to many bugs. It's better to just copy it and save yourself a hassle in the future.
In case you want to filter a book away, you can just change it like this:
setOwnerInfo(owners => owners.map(owner => {
// First check for correct owner. Return if this is wrong one.
if (owner.onwer !== "John Doe") { return owner }
// Filter here
// Let's create a new object, instead of mutating it.
return {...owner, booksOwned: owner.booksOwned.filter(ownedBook => ownedBook !== newBook)}
}))
This should remove all array items that match newBook (even if somehow there are duplicates, which shouldn't happen since we're guarding against duplicates above).
Upvotes: 2
Reputation: 1975
Here is an easy way to do this in ES6 Javascript:
// owner set to name of the owner
// newBook set to book title
const addBook = (owner, newBook) => {
// Find owner by name
const person = ownerInfo.find(person => person.owner === owner)
// if book already owned escape function
person.booksOwned.find(exists => { if(exists == newBook) return })
// Add book to owned books
person.booksOwned.push(newBook)
}
// example on how to use
addBook("John Doe", "New Book")
Or if you want to use it with setState:
const addBook = (owner, newBook) => {
const person = ownerInfo.find(person => person.owner === owner)
const newOwnerInfo = person.booksOwned.push(newBook)
person.booksOwned.find(exists => { if(exists == newBook) return })
setOwnerInfo(newOwnerInfo) // to change state
}
This function can be used for any of the owners.
Hope this helps.
Upvotes: 1