this is my state
const [dataItem, setDataItem] = useState({
id: null,
code: null,
title: null,
prent: null,
unitId: null,
});
and i want append file to dataItem state
let file = [
{
uid: '1',
name: items.file,
status: 'done',
},
];
setDataItem({ ...dataItem, file });
but it instead of append to dataItem , it replaced and other elements(e.g id, code, title) will be null
dataItem state after append file
{
"id": null,
"code": null,
"title": null,
"prent": null,
"unitId": null,
"file":[{
"uid": "1",
"name": "u104.svg",
"status": "done"
}]
}
Because the state was initialized to an object instead of an array. It should be
const [dataItem, setDataItem] = useState([{
id: null,
code: null,
title: null,
prent: null,
unitId: null,
}]);
When update dataItem, you have to spread array file too
setDataItem({ ...dataItem, ...file });
Read more =>
Correct modification of state arrays in ReactJS
To append file keeping the previous state intact, you'll need to use functional updates.
let file = [
{
uid: '1',
name: items.file,
status: 'done',
},
];
setDataItem(prevState => ({ ...prevState, file }));
Related
I'm facing a problem accessing initialstates array of object for redux.
I have this initial states:
export const initialState = [
{
blogPosts: [
{
title: "",
category: "",
logo: "",
author: "",
date: "",
timeToRead: "",
blogImage: "",
},
],
},
{ filterStatus: "" },
{ filterBy: "" },
];
and I only want to change the filterStatus from my reducer. But trying to do so its changing and also adding one more object in the array.
I was trying this code from my reducer:
case SEARCH_AUTHOR:
return [
...state,
(state[1].filterStatus = "author"),
];
How can I change get rid of this problem?
What you are doing here:
case SEARCH_AUTHOR:
return [
...state,
(state[1].filterStatus = "author"),
];
Is creating a new object with the entirety of state - (...state)
And then modifying the 2nd item's filter status, but only returning the result of the expression which is the newly set value "author".
There are many ways to implement what you wanted, I think the simplest would be to copy the array then modify the copy before returning.
case SEARCH_AUTHOR:
const copy = [...state]
copy[1] = {...copy[1], filterStatus: 'author'}
return copy;
What this does is:
Create a shallow copy of the array - this copies the same object references to a new array
Overwrite item at index 1 with a new object that spreads (copies) the original and then overwrites the required key
Another possible solution would be to use map or reduce on the array and returning the modified new array, or splice a new object at the correct index
You can use splice state.splice(1, 1, { filterStatus: "author" } to remove the { filterStatus: "" } and set instead { filterStatus: "author" } and return a copy of the state by return [...state].
const initialState = [
{
blogPosts: [
{
title: "",
category: "",
logo: "",
author: "",
date: "",
timeToRead: "",
blogImage: "",
},
],
},
{ filterStatus: "" },
{ filterBy: "" },
];
const changeFilter = () => {
initialState.splice(1, 1, { filterStatus: "author" } )
return [ ...initialState ];
}
console.log(changeFilter())
Use var instead of const
export var initialState = [
{
blogPosts: [
{
title: "",
category: "",
logo: "",
author: "",
date: "",
timeToRead: "",
blogImage: "",
},
],
},
{ filterStatus: "" },
{ filterBy: "" },
];
I am using the value of a multi nested (Infinity level) reactive form which contains formArray, formGroups and formControls. Which is stored in DB.
Currently, I am patching the form using a recursion function that loops through the entire JSON and makes formArrays, formGroups and formControls based on keys and values.
Now the issue is, this method which I am using is not good as per performance perspective, so is there any better way to patch this kind of multi nested form in one go? (Just create form, no need to show in HTML)
This is simplified JSON for question reference -
Any section can have subSections and then subSections can have some kind of section
const formDataSections = [
{
index: 1,
sectionName: "",
subSections: [
{
index: 1,
subSectionName: "",
sections: [
{
index: null,
sectionName: "",
subSections: [
{
index: null,
subSectionName: "",
sections: [
{
index: null,
sectionName: "",
},
{
index: null,
sectionName: "",
subSections: [
{
index: null,
subSectionName: "",
sections: [
{
index: null,
sectionName: "",
},
{
index: null,
sectionName: "",
subSections: [],
},
],
},
],
},
],
},
],
},
{
index: null,
sectionName: "",
subSections: [
{
index: null,
contentTypes: [],
sections: [
{
index: null,
sectionName: "",
subSections: [],
},
],
},
],
},
],
},
],
},
];
You could create a custom "subform" component using ControlValueAccessor (docs) and call the component recursively (example)
I don't think you can avoid recursion since the list has potentially infinite length
Here's a (not fully working...) StackBlitz example, just to showcase what I'm talking about.
I'm working on a react app to create multiple utm urls for ad campaigns and I'm having difficulty assigning values to the array in this.state. Here is how I establish the state:
constructor() {
super();
this.state = {
urlTabs: [
{
retailer: "",
product: "",
source: "",
medium: "",
campaign: "",
keyword: "",
identifier: "",
notes: "",
url: "",
productOptions: []
}
]
}
let tempTabs = [];
}
The app has the ability to have multiple urls that they are making at the same time which means that I needed to make state.urlTabs be an array of associative arrays. If they press a button I modify the state to have two arrays like such:
this.state = {
urlTabs: [
{
retailer: "",
product: "",
source: "",
medium: "",
campaign: "",
keyword: "",
identifier: "",
notes: "",
url: "",
productOptions: []
},
{
retailer: "",
product: "",
source: "",
medium: "",
campaign: "",
keyword: "",
identifier: "",
notes: "",
url: "",
productOptions: []
}
]
}
The issue I'm running into is when I'm trying to set any of the values. I do it by passing the event, input type and index as variables that then uses tempTabs to assign the individual value like such:
this.tempTabs[index]["source"] = event.target.value;
this.setState({
urlTabs: this.tempTabs
}
However for some reason every value of source gets changed rather than the one that I selected via index. Why is that? Am I using wrong syntax to access the values? How do I set only one of the associative array's source instead of all of them?
instead of creating a component level variable inside your class component like this.tempTabs try creating a variable like:
yourHandler = (e, idx) => {
const tempTabs = {...this.state.urlTabs}
tempTabs[idx]['source'] = e.currentTarget.value
this.setState({ urlTabs: tempTabs })
}
i think the problem is that you are creating tempTabs in component level!
I'm doing a request to an API that is successful but i need to get the data of the array returned, below i will put how the array looks like so you can help me to extract the data
{ total_grand: 30600000,
total_billable: null,
total_currencies: [ { currency: null, amount: null } ],
total_count: 5,
per_page: 50,
data:
[ { id: 13998122,
pid: 1570982183,
tid: null,
uid: 5386231,
description: 'Finish the first part of the RCP mockup',
start: '2020-03-26T13:00:00-04:00',
end: '2020-03-26T16:00:00-04:00',
updated: '2020-04-02T13:25:15-04:00',
dur: 10800000,
user: 'Jose',
use_stop: true,
client: 'PLA',
project: 'Training',
project_color: '0',
project_hex_color: '#3750b5',
task: null,
billable: null,
is_billable: false,
cur: null,
tags: []
} ]
}
I want to access to the user,project,tags,client,start,end and description so i can put it in my SpreadSheet. How can i do that?
This is how i do the request and how i try to access to the data in the array in my variable togglData
for (var i = 0; i < projects.length; i++) {
var listProjects = projects[i];
var reportURL = baseURL + '/reports/api/v2/details' + params;
var reportFetch = UrlFetchApp.fetch(reportURL, options);
var togglReport = JSON.parse(reportFetch.getContentText());
var togglData = togglReport["data"]["user"];
Logger.log(togglReport);
}
Range.setValues() is used to the set data as a two dimensional array to the sheet. Using destructuring assignment and for...of loop, It's possible to mould the data to a 2D array.
const togglReport = {
total_grand: 30600000,
total_billable: null,
total_currencies: [{ currency: null, amount: null }],
total_count: 5,
per_page: 50,
data: [
{
id: 13998122,
pid: 1570982183,
tid: null,
uid: 5386231,
description: 'Finish the first part of the RCP mockup',
start: '2020-03-26T13:00:00-04:00',
end: '2020-03-26T16:00:00-04:00',
updated: '2020-04-02T13:25:15-04:00',
dur: 10800000,
user: 'Jose',
use_stop: true,
client: 'PLA',
project: 'Training',
project_color: '0',
project_hex_color: '#3750b5',
task: null,
billable: null,
is_billable: false,
cur: null,
tags: [],
},
],
};
const out = [];
for (const {
user,
project,
tags,
client,
start,
end,
description,
} of togglReport.data) {
//We're looping over togglReport.data and not togglReport
out.push([user, project, tags.join(), client, start, end, description]);
}
console.log(out);
//SpreadsheetApp.getActive().getSheets[0].getRange(1,1, out.length, out[0].length).setValues(out);
I have a datatable where I am using a framework.
For now I am only mocking data because I don't have straight directions from my boss yet.
In the datatable docs say this:
rows:
The rows prop is where you provide us with a list of all the rows that you want to render in the table. The only hard requirement is that this is an array of objects, and that each object has a unique id field available on it.
headers:
The headers prop represents the order in which the headers should appear in the table. We expect an array of objects to be passed in, where key is the name of the key in a row object, and header is the name of the header.
The headers are going to be hardcoded:
For that I have this:
const tableHeaders = [
{
key: 'device',
header: t('cancellations.device'),
},
{
key: 'ticketNumber',
header: t('cancellations.ticketNumber'),
},
{
key: 'itemsCancelled',
header: t('cancellations.itemsCancelled'),
},
{
key: 'requestDate',
header: t('cancellations.requestDate'),
},
{
key: 'status',
header: t('cancellations.status'),
},
{
key: 'requestedBy',
header: t('cancellations.requestedBy'),
},
];
And before I had this hardcoded which is what I need to model and keep it exactly as it is, not hardcoded but with real data:
const rows = [
{
id: 'a',
device: t('Device 1'),
ticketNumber: t('Ticket Number'),
itemsCancelled: t('Items Cancelled'),
requestDate: t('Request Date'),
status: t('Status'),
requestedBy: t('Requested By'),
},
{
id: 'b',
device: t('Device 2'),
ticketNumber: t('Ticket Number'),
itemsCancelled: t('Items Cancelled'),
requestDate: t('Request Date'),
status: t('Status'),
requestedBy: t('Requested By'),
},
{
id: 'c',
device: t('Device 3'),
ticketNumber: t('Ticket Number'),
itemsCancelled: t('Items Cancelled'),
requestDate: t('Request Date'),
status: t('Status'),
requestedBy: t('Requested By'),
}
];
And the real data comes like this:
"CancellationRequests": [
{
"accountId": 232279,
"billingCancelReasonId": null,
"createDate": "2018-09-18T11:28:47-07:00",
"id": 17195077,
"modifyDate": "2018-09-18T11:28:48-07:00",
"notes": null,
"statusId": 2,
"ticketId": 65626859,
"account": null,
"items": null,
"status": null,
"ticket": null,
"user": null,
"itemCount": null,
"__typename": "SoftLayer_Billing_Item_Cancellation_Request"
},
{
"accountId": 232279,
"billingCancelReasonId": null,
"createDate": "2018-09-10T11:11:05-07:00",
"id": 17183859,
"modifyDate": "2018-09-10T11:11:06-07:00",
"notes": null,
"statusId": 2,
"ticketId": 65169379,
"account": null,
"items": null,
"status": null,
"ticket": null,
"user": null,
"itemCount": null,
"__typename": "SoftLayer_Billing_Item_Cancellation_Request"
}
]
So, comparing the real data with the hardcoded rows, it should match like this:
id: row.id,
device: row.account,
ticketNumber: row..ticketId,
itemsCancelled: row.itemCount,
requestDate: row.createDate
status: row.status,
requestedBy: row.user,
I am getting the values like this:
data.SoftLayerCancellationRequests.map(item => item);
But I don't know how to assign them to the proper key: value in a new object.
PS: I am using Reactjs.
Library use for components: http://react.carbondesignsystem.com/?selectedKind=DataTable&selectedStory=with%20expansion&full=0&addons=1&stories=1&panelRight=0&addonPanel=REACT_STORYBOOK%2Freadme%2Fpanel
You have already done all the hard work. It's just a matter of creating a new mapped array using your key matching already shown in your question
const rows = APIArray.map(row => {
return {
id: row.id,
device: row.account,
ticketNumber: row.ticketId,
itemsCancelled: row.itemCount,
requestDate: row.createDate
status: row.status,
requestedBy: row.user
}
})