Finding an array item in state - reactjs

I have the following array in my Sate:
this.state = {
currentAsset: null,
assets: [
{ id: uuidv4(), selected: false, text: 'Sorte',},
{ id: uuidv4(), selected: false, text: 'optical_dillusion2322.jpg'},
{ id: uuidv4(), selected: false, text: 'man_read_abook3242332.jpg'},
]
}
I want to find one of these assets and assign it to currentAsset. I have the following function:
handleAssetIDChange(assetID) {
console.log(assetID)
var currentAsset = this.state['assets'][assetID]
console.log(currentAsset)
// this.setState({
// currentAsset: this.state['assets'][assetID],
// openAssetSideBar: true
// }, () => {
// console.log(this.state['assets'][assetID])
// })
}
You can see the commented out part is now working. I am trying to set the currentAsset and then trigger the open of the sidebar to display the contents, but currentAsset is not getting set.
I have the assetID, how can I locate the one I need? Another question i have is in many stackoverflow posts they reference state vars like objects, aka:
this.state.assets but I always get an error when trying to do that.
How can I assign currentAsset and then trigger the openAssetSidebar when it has been set?

I would use a filter use get the object, this should update your currentAsset in the state.
handleAssetIDChange(assetID) {
console.log(assetID)
var currentAsset = this.state['assets'].filter( item => item.id === assetID)[0]
console.log(currentAsset)
this.setState(( prev ) => {
...prev,
currentAsset,
openAssetSideBar: true
})
}

In order to find the asset that you are looking for with a specific id, instead of
var currentAsset = this.state['assets'][assetID]
You should do:
const foundAsset = this.state['assets'].find((el) => el.id === assetID)
then to update the state, you would do:
this.setState((prev) => ({...prev, currentAsset: foundAsset}))

Related

Update nested React state?

I'm trying to update part of a state object that is nested. This is the object:
const [buttonObject, setButtonObject] = useState({
intro: [
{
id: '123',
name: 'first_intro_name',
selected: false,
},
{
id: '124',
name: 'second_intro_name',
selected: false,
},
],
experience: [
{
id: '789',
name: 'first_experience_name',
selected: false,
},
{
id: '8910',
name: 'second_experience_name',
selected: false,
},
],
});
When a button is clicked I want to toggle the selected state. I'm using a click handler that looks like this:
const handleButtonClick = ({ id, selected }) => {
if (id === '123') {
buttonsObject.intro.map(
pref => (pref.selected = pref.id === id ? !pref.selected : selected)
);
setButtonsObject(buttonsObject);
} else if (id === '124') {
buttonsObject.intro.map(
pref => (pref.selected = pref.id === id ? !pref.selected : selected)
);
setButtonsObject(buttonsObject);
}
};
It would handle experiences as well. The issue is that right now it seems like rather than updating the object it just overwrites the object or creates a new one. It also doesnt pass that information back down to the component even though I have it routed correctly so it should.
Is there better/correct syntax for updating nested state like this?
Thanks.
instead of checking again with if condition use higher order array function and spread operator to get optimal solution.
setButtonObject(previous => {
return {
...previous,
info: previous.info.map(item => item.id === id ? {
...item,
selected: true
} ? item)
}
})

Update value in nested object using React Hooks

My desire is to update the products inside the shoppingCart[0]
The state: const [authenticatedUser, setAuthenticatedUser] = useContext<any>(UserContext)
console.log(authenticatedUser) displays the following:
I've tried updating the value of the products array with the following code:
setAuthenticatedUser({ ...authenticatedUser, products: ['new item'] })
But it creates a new product array inside the authenticatedUser.
How can I update the products array inside authenticatedUser.shoppingCart[0].products ?
Data:
const [authenticatedUser, setAuthenticatedUser] = useState(
{
authenticated: true,
id: "3i4jijrifjifrjifr",
shoppingCart: [{
createdAt: "2021-01-29T10:14:21.253Z",
products: ['this is the array i want to update', '2', '3']
}]
}
)
try this:
setAuthenticatedUser({ ...authenticatedUser, shoppingCart:[{...authenticatedUser.shoppingCart[0],products:['newItem']}] })
const authenticatedUserCopy = { ...authenticatedUser }
authenticatedUserCopy.shoppingCart[0].products = ['new product']
setAuthenticatedUser(authenticatedUserCopy)
{
...authenticatedUser,
shoppingCart: authenticatedUser.shoppingCart.map(s => { //map all items
return {
...s,
products: [...s.products, 'new item'] //add item
}
})
}

Adding to an array within an array state in ReactJS

I'm trying to add functionality for adding to a state, more specifically "list", in the following state:
shoeList : [
{name: 'Nike',
list : [
{type: 'boots', revenue: '1000000', gender: 'mens', price: '49.99', id: 3},
{type: 'shoes', revenue: '13280100', gender: 'womens', price: '99.99', id: 2}
]
}
],
Right now I have a component that displays a form for the user to enter new values for type revenue gender and price.
Here is the code for the component(not including the forms and text input html):
state = {
}
//when changes occur in text input fields
handleChange = (e) => {
this.setState({
[e.target.id]: e.target.value
})
}
handleSubmit = (e) => {
e.preventDefault();
this.props.addShoe(this.state);
And in the root component i have the addShoe function:
addShoe = (shoe) => {
shoe.list.id = Math.random();
//returns a new array so no alteration of original array
let shoeList = [...this.state.shoeList, shoe];
this.setState({
shoeList: shoeList
})
}
Trying this code gives me an error saying shoe.list.id is undefined? Also I think I'm missing something to add in the component file specifically in the state. Also is there any way to directly access list like this.state.shoeList.list? I'm not sure if i have to add list to shoeList. Any help would be great thanks
In your example, if the intention is to add an item to specifically the Nike list:
addShoe = (shoe) => {
this.setState({
// return an altered copy of the array via map
shoeList: this.state.shoeList.map(brandItem => {
if (brandItem.name === 'Nike') {
return {
// use spread syntax for other object properties to persist
...brandItem,
list: [
// use spread syntax to keep the original items in the list
...brandItem.list,
{
// assuming shoe is an object without an id property
...shoe,
id: Math.random()
}
]
}
} else {
return brandItem;
}
})
}

How to update a state which is a array of objects?

My state is as follows
this.state = {
todos: [{
title: 'asas',
status: 'incomplete',
uuid: 11
}, {
title: 'asas',
status: 'incomplete',
uuid: 12
}, {
title: 'asas',
status: 'complete',
uuid: 13
}],
currentTab: "Show All"
}
and whenever a user clicks on any of the todo items's checkBox i want to update the state status of the checkbox and i have written the following code for it
this.state.todos.map(todo => {
if (todo.uuid === uuid) todo.status = (todo.status === 'complete') ? 'incomplete' : 'complete'
});
this.forceUpdate();
Is Using forceUpdate a good approach here? as i have updating only a single value inside an array of objects. Is there a better solution for this problem?
either of the following will call setState with the updated state without modifying the current state.
https://redux.js.org/recipes/structuringreducers/immutableupdatepatterns#inserting-and-removing-items-in-arrays
using the spread operator:
edit.. actually, this is the hard way 8)
see https://redux.js.org/recipes/structuringreducers/immutableupdatepatterns#updating-an-item-in-an-array
this.setState(prevState => {
const idx = prevState.todos.findIndex(todo => todo.uuid === uuid);
return {
todos: [
...prevState.todos.slice(0, idx),
{
...prevState.todos[idx],
status: prevState.todos[idx].status === "complete" ? "incomplete" : "complete",
}
...prevState.todos.slice(idx + 1),
]
}
});
or using immer:
import produce from "immer";
this.setState(prevState => {
const idx = prevState.todos.findIndex(todo => todo.uuid === uuid);
return produce(prevState, draft => {
draft.todos[idx].status = prevState.todos[idx].status === "complete" ? "incomplete" : "complete"
});
});

React Duplicate Key Error

I'm getting the following error, I understand what its telling me but I can't figure out how to solve the issue.
flattenChildren(...): Encountered two children with the same key...
I have 2 lists on my page which contain emails. The initial state of my app contains the following data:
const initialState = {
emails: [
{
id: 1, from: 'test.1#test.co.uk', body: 'test1 body', title: 'test 1 title',
},
{
id: 2, from: 'test.2#test.co.uk', body: 'test2 body', title: 'test 2 title',
},
],
draggedEmails: [],
};
The UI of my app lets you drag and drop items from the first list (emails) to the second list (draggedEmails).
In my Redux reducer I have the following code to move emails between the lists.
let newState = {};
//Check if the email exists in my 'emails' array
const doesExistInEmails = state.emails.find(x => x.id === action.id) !== null;
//If it exists then move it to the 'draggedEmails' list
if (doesExistInEmails) {
const filteredEmails = state.emails.filter(e => e.id !== action.emailItem.id);
newState = Object.assign(
{},
state,
{ draggedEmails: [...state.draggedEmails, action.emailItem], emails: filteredEmails }
);
} else {
const filteredEmails = state.emails.filter(e => e.id !== action.emailItem.id);
newState = Object.assign(
{},
state,
{ draggedEmails: [...state.emails, action.emailItem], emails: filteredEmails });
}
return newState;
The problem occurs when I move the items BACK to the emails list, once they have been moved to the 'draggedEmails' list.
The following code is what is used to create the elements and the keys.
createEmailItem(em) {
return React.createElement(
EmailItem, { email: em, key: `${em.id}` });
}
Any help is appreciated,
Thanks.
EDIT: Console.Logged state after moving one item from the 'emails' list to the 'draggedEmails' list. Everything looks as it should.
Object {emails: Array[1], draggedEmails: Array[1]}
EDIT2: Adding render method.
render() {
return (
<div className="email-container" onDrop={this.onDrop} onDragOver={this.allowDrop}>
{this.props.emails.map(this.createEmailItem)}
</div>
);
}
I found the problem. There were 4.
The first is that the following was returning 'undefined' rather than 'null'
const doesExistInEmails = state.emails.find(x => x.id === action.id) !== null;
The second is that my action doesn't have an id, my action has an emailItem which has an id
const doesExistInEmails = state.emails.find(x => x.id === action.emailItem.id) !== undefined;
The third is that I was filtering my emails rather than dragged emails in the following line.
const filteredEmails = state.filter(e => e.id !== action.emailItem.id);
And finally I was assigning the wrong values back when setting the state.
{ draggedEmails: [...state.emails, action.emailItem], emails: filteredEmails });
Should be...
{ emails: [...state.emails, action.emailItem], draggedEmails: filteredEmails });
So overall, I had lots wrong...
Thanks to the guys who commented.

Resources