How do I concat two objects into one - React-Native state - reactjs

Here are two objects one is creating onload of page while another is I want to add on button click into the current state
constructor(props){
super(props);
this.state = {
marked: null,
tempMarkedDates: [],
}
this.toggle = this.toggle.bind(this);
}
// First object into marked is like
console.log(JSON.stringify(this.state.marked));
Output ::
[
{
"2019-01-02":{
"disabled":true,"selected":true,"selectedColor":"#10cc74"
},
"2019-01-04":{
"disabled":true,"selected":true,"selectedColor":"#10cc74"
},
"2019-01-08":{
"disabled":true,"selected":true,"selectedColor":"#10cc74"
},
"2018-12-29":{
"disabled":true,"selected":true,"selectedColor":"#10cc74"
},
"2018-11-27":{
"disabled":true,"selected":true,"selectedColor":"#fc3232"
},
}
]
Working from my own answer here on stack overflow
//Now I am creating new object like
day = "2019-01-10"
let obj = {};
obj[day] = {
disabled: true,
selected: true,
selectedColor: '#fc3232'
}
//So the output will be
[
{
"2018-12-30":{
"disabled":true,"selected":true,"selectedColor":"#10cc74"
}
}
]
I want to merge both the object and update this.state.marked
And it should be remain object after concatenation, while my code is changing it into array
Desire Output - Need to join last or first date object of 30-12-2018
[
{
"2019-01-02":{
"disabled":true,"selected":true,"selectedColor":"#10cc74"
},
"2019-01-04":{
"disabled":true,"selected":true,"selectedColor":"#10cc74"
},
"2019-01-08":{
"disabled":true,"selected":true,"selectedColor":"#10cc74"
},
"2018-12-29":{
"disabled":true,"selected":true,"selectedColor":"#10cc74"
},
"2018-11-27":{
"disabled":true,"selected":true,"selectedColor":"#fc3232"
},
"2018-12-30":{
"disabled":true,"selected":true,"selectedColor":"#10cc74"
}
}
]
So need your help to concat the both object for React native state.

We can use the assign() method of javascript.
Reference: https://stackoverflow.com/a/51143342/3449578
let newstate = Object.assign(obj , this.state.marked[0])
this.setState({marked: newstate });

You can use ... spread operator inside this.setState:
var obj = {
"2019-01-02":{
"disabled":true,"selected":true,"selectedColor":"#10cc74"
},
"2019-01-04":{
"disabled":true,"selected":true,"selectedColor":"#10cc74"
},
"2019-01-08":{
"disabled":true,"selected":true,"selectedColor":"#10cc74"
},
"2018-12-29":{
"disabled":true,"selected":true,"selectedColor":"#10cc74"
},
"2018-11-27":{
"disabled":true,"selected":true,"selectedColor":"#fc3232"
},
}
console.log(obj)
var s = {...obj,
"2018-12-30":{
"disabled":true,"selected":true,"selectedColor":"#10cc74"
}
}
console.log(s)
In React you can do this by:
this.setState({ marked: {...this.state.marked, "2018-12-30":{
"disabled":true,"selected":true,"selectedColor":"#10cc74"
}})

This is how I would do it in react. Keep your whole state and update the marked with new values using setState.
Just provide values to the handleMarked function to update the state. And delete dummy values for day and value.
constructor(props) {
super(props);
this.state = {
marked: {},
tempMarkedDates: [],
}
this.toggle = this.toggle.bind(this);
}
handleMarked = (day, value) => {
/* Provide values to function params above and delete dummy values below */
day = '2019-01-10';
value = {
disabled: true,
selected: true,
selectedColor: '#fc3232'
}
this.setState({
...this.state,
marked: {
...this.state.marked,
[day]: value
}
},
() => console.log(JSON.stringify(this.state.marked))
);
}

Related

update nested state object with array inside

I am having trouble updating my state object that has an array of objects inside. There are few things that I have tried but none of them worked. Here is an example of my state object. With the example below, I want to update the values for test and test2 depending on whatever the user types in input field. Can someone guide me in the right direction. Thank you!
this.state = {
someProperty: {
someOtherProperty: [
object in array: {
test: true,
test2: false
},
object in array: {
test: true
test2: false
}
..
]
...
}
...
}
My attempt on updating the value inside the object is as follows:
this.setState(prevState => ({
...prevState,
someProperty: {
...prevState.someProperty,
someOtherProperty: [
...prevState.someProperty.someOtherProperty,
test: false
]
}
}))
You can create an array latestSomeOtherProperty, update the wanted index and then;
const latestSomeOtherProperty = someOtherProperty.map(prop=>{...prop, test: false}); // it updates all but you can put condition here
this.setState(prevState => ({
...prevState,
someProperty: {
...prevState.someProperty,
someOtherProperty: [
...latestSomeOtherProperty
]
}
}))

Push value of arrivalDate in array

I would like to store every arrivalDate in my array list.
Someone could tell me how can I do it?
But my array is still empty.
JSON returned by the API:
{
"reservations": {
"reservationInfo": [
{
"roomStay": {
"arrivalDate": "11am"
},
"WeatherR": {
"sound": "cloudy"
},
},
{
"roomStay": {
"arrivalDate": "7pm"
},
"WeatherR": {
"sound": "cloudy"
},
}
]
}
}
component.ts
searchForReservation() {
alert('hello');
this.http.get('/api/searchForReservation')
.subscribe((data) => {
this.ddataIno = data;
this.ddataIno = this.ddataIno.result.reservations.reservationInfo;
console.log('number of value', this.ddataIno.length);
console.log('content', this.ddataIno);
for (let i = 0; i <= this.ddataIno[i].length; i++) {
this.list = this.ddataIno.roomStay.arrivalDate;
}
console.log('store array', this.list)
})
}
searchForReservation() {
alert('hello');
this.http.get('/api/searchForReservation')
.subscribe((data) => {
const reservationInfo = this.data.result.reservations.reservationInfo;
this.list = reservationInfo.map(e => e.roomStay.arrivalDate);
})
}
Here's a working example in vanilla JS. You would need to make some small adjustments for angular, like this.list = ... instead of let list = ...
Using Array#map, you can create a new array from the JSON object
data.reservations.reservationInfo.map(r => r.roomStay.arrivalDate)
let data = {
"reservations": {
"reservationInfo": [{
"roomStay": {
"arrivalDate": "11am"
},
"WeatherR": {
"sound": "cloudy"
},
},
{
"roomStay": {
"arrivalDate": "7pm"
},
"WeatherR": {
"sound": "cloudy"
},
}
]
}
}
// declare your list as an array at the top
// list: []
// below would start off as 'this.list'
let list = data.reservations.reservationInfo.map(r => r.roomStay.arrivalDate);
console.log(list);
Your for loop is just reassigning the value of this.list
I suggest reading up on Array methods
I would use a map method, e.g.
this.list = this.ddataIno.result.reservations.reservationInfo.map(i => i.roomStay.arrivaldate);

immutable helper updating value in object in array

I'm trying to understand immutable helper in the context of what I'm trying to do.
I'm trying to update the objects inside based on when an onChange event calls the INPUT_CHANGE action. it should add to the formData value not replace it. I tried $add but that didn't work the way I wanted it either.
Also every time a a new input filed is changed it adds a new object with the same updated changes.
Array[index] -> input1 -> INPUT_CHANGE -> update object with key and value of input field as it changes.
inputs=[{key:{key:'input name', value: mew}}]
Array[index] -> input2 -> INPUT_CHANGE -> update object with key and value of input field as it changes.
inputs=[{key:{key:'input name', value: mew}}, {key:{key:'input name', value: mew}}]
and so on ...
const setupState = {
count: 0,
inputs: [{}],
};
export default (state = setupState, action) => {
switch (action.type) {
case INPUT_CHANGE: {
// const formDataArr = state.inputs[count];
return update(state, {
inputs: [{
key: { $set: action.key },
value: { $set: action.value },
}],
});
}
default: return state;
}
};
Kind of confused as to how to use immutable helper for this ?
UPDATE:
This is how the the object should look as user updates each input.
inputs: [
{
"score": {
"key": "score",
"value": "20....",
},
"hits": {
"key": "hits",
"value": "ss..",
}
}
]
Try this.
export default (state = setupState, action) => {
switch (action.type) {
case INPUT_CHANGE: {
// const formDataArr = state.inputs[count];
return update(state, {
inputs: [
// contain origin state.inputs!!!!!!!!!!!!!!!!!!!
...state.inputs,
{
key: { $set: action.key },
value: { $set: action.value },
}],
});
}
default: return state;
}

SetState not working with spread operator

I have a language switcher in a React native app, it has the selected language ticked, which is stored in state. However this is not working, any advice appreciated. The code is as below. The selectedLanguage is being populated so it knows what needs updating but it's not updating the state object.
constructor(props) {
super(props);
this.state = {
languages: [
{
language: 'Dutch',
selected: false,
},
{
language: 'English',
selected: true,
},
{
language: 'French',
selected: false,
},
{
language: 'German',
selected: false,
},
{
language: 'Polish',
selected: false,
}
],
};
};
changeLanguage(selectedLanguage){
this.state.languages.map((language) => {
if(language.language === selectedLanguage){
this.setState(prevState => ([
...prevState.languages, {
language: selectedLanguage,
selected: true,
}
]));
}
});
}
The spread operator isn’t going to deep compare objects in an array. You’ve got to either move from a languages array to a languages object, as in:
languages: {
Dutch: false,
English: true,
...
}
Or, you need to copy and replace:
changeLanguage(selectedLanguage){
this.state.languages.map((language, index) => {
if(language.language === selectedLanguage){
this.setState(prevState => {
const newLangs = [...prevState.languages];
newLangs[index].selected = true;
return newLangs;
});
}
});
}
First need to find out the right object for given selectedLanguage from an array.
Use Array#map to traverse and update the matched object selected prop value with boolean true and rest to false.
const {languages} = this.state;
const updatedLang = languages.map((lang, key) => {
if (lang.language == selectedLanguage) {
lang.selected = true;
} else {
lang.selected = false;
}
return lang;
})
Now do setState.
this.setState(prevState => ({languages: updatedLang}));

Unable to update redux store on manipulating the initial state

Using this action for updating the particular componentId in redux initial state. Facing 6the following violation error while updating the initial state.
Uncaught Invariant Violation: A state mutation was detected between dispatches, in the path "currentActivityJSON.draggedItems.1.isDisable". This may cause incorrect behavior. (http://redux.js.org/docs/Troubleshooting.html#never-mutate-reducer-arguments)
Code:
export function draggedItem(currentActivityJSON, componentId) {
let draggedItems = currentActivityJSON.draggedItems;
for (var i=0; i < draggedItems.length; i++ ) {
if (componentId === draggedItems[i].componentId) {
draggedItems[i ].isDisable = true;
}
}
return {
type: DRAGGED_ITEM,
currentActivityJSON: Object.assign({}, currentActivityJSON, {
...currentActivityJSON,
draggedItems: draggedItems
})
};
}
This is initial_state.json and need to update the 2nd array item `isDisable=true.
"currentActivityJSON": {
"defaultItems": [],
"expectedItems": [
"GLASS_BOTTLE"
],
"isDoneEnabled": true,
"draggedItems": [
{
"imageUrl": "../src/media/images/activities/box_big#2x.png",
"componentId": "CARTBOARD_BOX",
"componentText": "CardBoard Box",
"width": "100%",
"height": "70%",
"isDisable": false
},
{
"imageUrl": "../src/media/images/activities/bottle_big#2x.png",
"componentId": "PLASTIC_BOTTLE",
"componentText": "Plastic 2L Bottle",
"width": "50%",
"height": "50%",
"isDisable": false
},
{
"imageUrl": "../src/media/images/activities/glasstank_big1#2x.png",
"componentId": "GLASS_BOTTLE",
"componentText": "Glass Tank",
"width": "80%",
"height": "70%",
"isDisable": false
}]
}
This piece of the code mutates items in the original draggedItems array:
let draggedItems = currentActivityJSON.draggedItems;
for (var i=0; i < draggedItems.length; i++ ) {
if (componentId === draggedItems[i].componentId) {
draggedItems[i ].isDisable = true;
}
}
Instead create a new draggedItems array, replace the changed item:
const draggedItems = currentActivityJSON.draggedItems.map((item) => {
if(componentId === draggedItems[i].componentId) {
return {
...item,
isDisable: true
};
}
return item;
});
Avoid mutations outside of the reducer by instantly returning the action in the action creator. Instead of for-loops, use ES6 spread and array methods.
export function draggedItem(currentActivityJSON, componentId) {
return {
type: DRAGGED_ITEM,
currentActivityJSON: {
...currentActivityJSON,
draggedItems: [
...currentActivityJSON.draggedItems.filter(item => item.componentId !== componentId), {
...currentActivityJSON.draggedItems.find(item => item.componentId === componentId),
isDisable: true
}
]
})
};
}
By the way, I wouldn't name it "JSON" becaus in JavaScript, it is just an object (literal). And if you are using the object spread operator (...object), you don't really need to call Object.assign().
But I'm wondering, if it wouldn't be better to just dispatch the componentId in the action and perform the change of currentActivityJSON in the reducer.
This code works like a charm!
const draggedItems = currentActivityJSON.draggedItems.map((item) => {
if(componentId === draggedItems[i].componentId) {
return {
...item,
isDisable: true
};
}
return item;
});

Resources