How to Add Object to Array State in ReactJs? - reactjs

I have this array of objects state, and it is working fine.
I need add another object to it dynamically.
const [productData, SetProductData] = useState({
sizes: [
{id: 2, value: 'Small', isActive: false},
{id: 2, value: 'Medium', isActive: false},
{id: 2, value: 'Large', isActive: true},
{id: 2, value: 'X Large', isActive: false},
{id: 2, value: 'XX Large', isActive: false}
]
})
I tried to do it like this, but it is not working
const addObjectToArray = obj => {
SetProductData(current => [...current, obj]);
};
addObjectToArray( {id: 3, value: 'XXX Large', isActive: true} )
I also need to update it dynamically

You need to keep the same structure in your state. You had an object, and you're changing it to an array. So
const addObjectToArray = obj => {
SetProductData(current => ({
...current,
sizes: [...current.sizes, obj]
}));
};
addObjectToArray( {id: 3, value: 'XXX Large', isActive: true} )

Related

How to set state in nested array of objects in ReactJs?

I have this object as a state in reactjs. I want to add another object inside the "childoptions: []" array which is nested inside the options array on button click.
How can I achieve this, pls help...
const [select1, setSelect1] = useState({
id: uuid(),
type: 'select',
properties: {
label: 'Select1',
options: [
// {
// id: uuid(),
// optionName: 'red 🔴',
// value: '',
// childOptions: [],
// },
// {
// id: uuid(),
// optionName: 'green 🟢',
// value: '',
// childOptions: [],
// },
// {
// id: uuid(),
// optionName: 'blue 🔵',
// value: '',
// childOptions: [],
// },
],
},
parentId: null,
});
This is achievable by copy the prevState in the new state with the new object inserted inside the options array.
A more detailed explanation could be found at https://stackoverflow.com/a/26254086/9095807
setSelect1((prevState) => {
return {
...prevState,
properties: {
label: 'Select1',
options: prevState.properties.options.map(obj => obj.id === id ? { ...obj, childOptions: [...obj.childOptions, newChildOptions] } : obj),
}
}
})

Map Angular Array to Object

I have been looking and have found a few good references for transforming arrays to objects, but I can't seem to find my use case. I have an array with the following format
[
{id: 1, name: 'hello', display: false},
{id: 5, name: 'hello2', display: true},
{id: 7, name: 'hello8', display: true},
]
and I would like to map it into something like this
{
5: {id: 5, name: 'hello2'},
7: {id: 7, name: 'hello8'}
}
I have been trying to use the map function, but I can't figure it out since I want the keys of my map to be an id. This is what I have so far but it is obviously wrong.
const myArray = [
{id: 1, name: 'hello', display: false},
{id: 5, name: 'hello2', display: true},
{id: 7, name: 'hello8', display: true},
];
const myMap = myArray.filter(row => row.display)
.map(row => {
return {row.id: {id: row.id, name: row.name}
});
Filter the array, map it to pairs of [id, obj], and convert to an object using Object.fromEntries(). You can use destructuring and rest syntax (...) to remove display.
Notes: if Object.fromEntries() is not supported, change target in TS Config to ES2019.
const arr = [{id: 1, name: 'hello', display: false},{id: 5, name: 'hello2', display: true}, {id: 7, name: 'hello8', display: true}]
const result = Object.fromEntries(
arr.filter(o => o.display)
.map(({ display, ...o }) => [o.id, o])
)
console.log(result)
Another option is to use Array.reduce() to create the object. In that case, you can skip objects with false display.
const arr = [{id: 1, name: 'hello', display: false},{id: 5, name: 'hello2', display: true}, {id: 7, name: 'hello8', display: true}]
const result = arr.reduce((acc, { display, ...o }) => {
if(display) acc[o.id] = [o.id, o]
return acc
}, {})
console.log(result)

how to update setstate array of object values in react js

How can I update setChoices object values, Below is an example of my problem:
I m having choices array of object with values. on setstate(setChoices) want to update the object values.
let [choices, setChoices] = useState({
Choices: [
{
OneChoiceWithValueSelected: {
OptionSelected: '15518',
Price: 0.9,
Quantity: 1,
},
ProductOptionId: 5712,
},
],
Note: 'test message',
ProductId: 6,
Quantity: 1,
StoreId: '6',
TableId: 0,
});
const demo = () => {
setChoices({
Choices: [
{
OneChoiceWithValueSelected: {
OptionSelected: '15518',
Price: 100,
Quantity: 12,
},
ProductOptionId: 5712,
},
],
Note: 'its a new message',
ProductId: 6,
Quantity: 10,
StoreId: '10',
TableId: 0,
});
alert(JSON.stringify(choices));
};
return (
<div>
<button onClick={demo}>test</button>
</div>
);
According to you're state structure, you have to update the setChoices part as follows
const demo = () => {
setChoices({
Choices[0].OneChoiceWithValueSelected.OptionSelected: '15518',
Choices[0].OneChoiceWithValueSelected.Price: 100,
Choices[0].OneChoiceWithValueSelected.Quantity: 12,
Choices[0].ProductOptionId: 5712,
Note: 'its a new message',
ProductId: 6,
Quantity: 10,
StoreId: '10',
TableId: 0
})
alert(JSON.stringify(choices))
}
you have to access the 0th array element to update it's attributes, because the OneChoiceWithValueSelected object is the first element of the Choices array and then use object notation to access others.

react-absolute-grid, displayObject issue

I am trying to use this component: https://github.com/jrowny/react-absolute-grid.
The documentation says I should pass a displayObject which renders items.
So I created a displayObject, like the one in the docs which has this render method:
render: function() {
// Supposing your item shape is something like {name: 'foo'}
const { item, index, itemsLength } = this.props;
return <div>Item {index} of {itemsLength}: {item.name}</div>;
}
I passed it to the component like this:
<AbsoluteGrid
items={SampleData.screens}
displayObject={<DisplayObject/>}
onMove={onMoveDebounced}
dragEnabled={true}
responsive={true}
verticalMargin={42}
itemWidth={250}
itemHeight={250}
filteredProp={'name'}
/>
Where SampleData.screens is:
module.exports = {
screens: [
{'url': 'http://invisionapp.com/subsystems/do_ui_kit/assets/img/screens/original-1x/screen-1-1-login.jpg', 'name': 'login', 'sort': 1, 'key': 1},
{'url': 'http://invisionapp.com/subsystems/do_ui_kit/assets/img/screens/original-1x/screen-1-2-sign-up.jpg', 'name': 'signup', 'sort': 2, 'key': 2},
{'url': 'http://invisionapp.com/subsystems/do_ui_kit/assets/img/screens/original-1x/screen-1-3-walkthrough.jpg', 'name': 'walkthrough', 'sort': 3, 'key': 3}
]
};
When I open the page in the browser, I don't see the text from the displayObject.
How can I use the displayObject?
DisplayObject works good when is a function that return the render html, I try creating a different React.Component for it but got some issues
const items = [
{ key: "0", sort: 0, name: 'Test 1', filtered: false },
{ key: "1", sort: 1 ,name: 'Test 2', filtered: false },
{ key: "2",sort: 2, name: 'Test 3', filtered: false},
{ key: "3", sort: 3,name: 'Test 4', filtered: false }
]
function GridItem(props) {
const { item, index, itemsLength } = props;
return <div >
<span>{item.name}</span>
</div>;
}
const AbsoluteGrid = createAbsoluteGrid(GridItem);

How to change the state of some component with setInterval()?

How can I make so that every 2 seconds my state randomly changes? For now it changes in console log but it doesn't render it. The active state change is supposed to change the Switch component visually. For example, if I exclude boxList[0].machines[0].switches[0].active = true it changes correctly but when it's within setInterval() it doesn't change anything.
Example:
App.js
var boxList= [
{id: 1, machines:[
{id: 1, switches:[{id: 1, active: false}, {id: 2, active: false}, {id: 3, active: false}, {id: 4, active: false}]},
{id: 2, switches:[{id: 1, active: false}, {id: 2, active: false}, {id: 3, active: false}, {id: 4, active: false}]},
{id: 3, switches:[{id: 1, active: false}, {id: 2, active: false}, {id: 3, active: false}, {id: 4, active: false}]},
{id: 4, switches:[{id: 1, active: false}, {id: 2, active: false}, {id: 3, active: false}, {id: 4, active: false}]},
]},
{id: 2, machines:[
{id: 1, switches:[{id: 1, active: false}, {id: 2, active: false}, {id: 3, active: false}, {id: 4, active: false}]},
{id: 2, switches:[{id: 1, active: false}, {id: 2, active: false}, {id: 3, active: false}, {id: 4, active: false}]},
{id: 3, switches:[{id: 1, active: false}, {id: 2, active: false}, {id: 3, active: false}, {id: 4, active: false}]},
{id: 4, switches:[{id: 1, active: false}, {id: 2, active: false}, {id: 3, active: false}, {id: 4, active: false}]},
]},
]}];
class App extends React.Component {
render() {
setInterval(() => {
var x = [0,1].sample()
var x = [0,1].sample()
var z = [0,1,2,3].sample()
var info = [true, false].sample()
boxList[x].machines[y].switches[z].active = info;
}, 2000);
var boxes = boxList.map((box) =>
<Box key={box.id} box_id={box.id} machines={box.machines} />);
return (
<div>
{boxes}
</div>
);
}
}
Your component doesn't have state, it accesses some globally available data. However, the actual problem is that you are never telling the component to rerender. The component doesn't know that the data is changed, hence it doesn't update.
If you don't want to move the data into the component's state, you can use forceUpdate to force a rerender.
But: The render method should never directly or indirectly goes another render. Having the setInterval call in render doesn't make much sense either, since this would create a new interval every time the component renders.
Instead, make use of the lifecycle methods and create the interval after the component mounted. Don't forget to clear the interval when the component is destroyed, too!
class App extends React.Component {
componentDidMount() {
this._interval = setInterval(() => {
// ...
this.forceUpdate();
}, 2000);
}
componentWillUnmount() {
clearInterval(this._interval);
}
render() {
// ...
}
}

Resources