how to set variable to empty array - javascript

I am trying to write a function that removes all the elements from an array called selectedItems.
It looks like this:
const selectNone = (e: any) => {
let selectedItemsCopy = selectedItems;
selectedItemsCopy = []
setState(
{
...state,
areAllSelected: false,
isChecked: false,
selectedItems: selectedItemsCopy
}
);
}
but in setState, selectedItems does not get updated to the empty copy of the array. What am I doing wrong?

The problem that you have is, that you are actually mutating state, which is basically prohibited in React. In this case, it's very simple to solve, just put the [] inside the setState directly, without any variables:
const selectNone = (e: any) => {
setState(
{
...state,
areAllSelected: false,
isChecked: false,
selectedItems: []
}
);
}
The method you are using to make a copy of the array, doesn't actually copy the array and instead just creates a reference to the original (that's how JS works). In order to make a proper copy (for example to be able to make modifications, not just clear the array), you should use Array.from().
Here's an example
const selectNone = (e: any) => {
let selectedItemsCopy = Array.from(selectedItems);
selectedItemsCopy[x] = changedValue;
setState(
{
...state,
areAllSelected: false,
isChecked: false,
selectedItems: selectedItemsCopy
}
);
}

Related

Using forEach on a nested object key react javascript

I have a nested object:
const refsObject = {
refOne: {
current: {
validate: function()
}
},
refTwo: {
current: {
validate: function()
}
}
};
I need to run input field validation using a single method that loops through each nested object of objects and invokes the validate method.
What I have tried up until now:
const splitObject = o => Object.keys(o).map(e => ({ [e]: o[e] }));
splitObject.forEach(ref => ref.current && ref.current.validate());
SplitObject returns me an array of objects with all the objects inside refsObject. Once I do forEach on splitObject it becomes undefined since ref.current is inside the nested object key "refOne" which is dynamic so I cannot hardcode. Any suggestion helps!
Is this what you're looking for?
const refsObject = {
refOne: {
current: {
validate: function() {
console.log('validate1');
}
}
},
refTwo: {
current: {
validate: function() {
console.log('validate2');
}
}
}
};
Object.values(refsObject).map(refs => refs.current.validate());
Run the validations on the original refsObject by taking the values, and iterating them with Array.forEach(). Use conditional chaining ?. to call the function in case current might be undefined:
const refsObject = {refOne:{current:{validate(){console.log('refOne')}}},refTwo: {current: {validate() {console.log('refTwo')}}}};
const runValidations = o => Object.values(o)
.forEach(ref => ref.current?.validate());
runValidations(refsObject);

.map not is not a function on empty object?

I am new to react. I have set up a reducer with the state as an empty object. But when using the .map() function it doesn't seem to work on the object? Does the .map only work on arrays?
export const orders = (state = {}, action) => {
const { type, payload } = action;
switch (type) {
case "NEW_ORDER":
const { new_order } = payload;
const new_state = { ...state, new_order };
console.log(new_state);
return new_state;
}
return state;
}
Well, no, you can not use .map() on an object since it is supposed to be used in an array. By the way, if you are trying to store a list of orders, you should use am array instead, so initialize your state with [] and not with {}, or with a key that actually contains your orders like { orders: [] } and then add the order you received like const new_state = { ...state, orders: [...state.orders, new_order] }.
You are correct. The map function is part of the Array prototype.
See here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map
However, I don't see a map function in the code sample you posted?
If you want to loop over an object though you can use Object.entries.
const myObj = {foo: "bar"}
const result = Object.entries(myObj).map(([key, value]) => {
console.log(key) // "foo"
console.log(value) // "bar"
return `${key}-${value}`
})
console.log(result) // ["foo-bar"]

Change Nested State Value With A Single Function? (javascript/React)

I have some react user privilege state data I need to manage. I would like the ability to change the object privileges based on their property through a dynamic function. I'm not sure how to target the specific nested privilege property to change the value. Is this possible?
Question: How can I change the value of a nested privilege property to the functions type and value parameter?
Heres an Example:
const [userPrivilages, setUserPrivilages] = useState([{
_id: "123"
privilages: {
edit: true, //before!
share: true,
del: false
}
},
{
...more users
}
])
//my attempt
const changePrivilage = (type, value) => {
const newPrivilages = userPrivilages.map(user => {
return {
...user,
privilages: {
...privilages,
//change the privilage of "type" from the functions parameter to the value parameter
}
}) setUserPrivilages(newPrivilages)
}
changePrivilage("edit", false)
Desired output:
const [userPrivilages, setUserPrivilages] = useState([{
_id: "123"
privilages: {
edit: false, //After!
share: true,
del: false
}
},
{
...more users
}
])
Thanks!
You can use [] to refer to variable as a key like below:
const changePrivilage = (type, value) => {
const newPrivilages = userPrivilages.map(user => {
return {
...user,
privilages: {
...user.privilages,
[type]: value // here it is !!!
}
}) setUserPrivilages(newPrivilages)
}
Try this :
(see comments for understanding code)
const changePrivilage = (type,value) => {
const newUserPrivilages = userPrivilages.map(user => {
let newPrivilages = user.privilages; // get old privilages of user
newPrivilages[type] = value; // update type with new value
return {
...user,
privilages: newPrivilages, // set privilages as newPrivilages
};
});
setUserPrivilages(newUserPrivilages);
};
Note : this will change properties for all users. If you want to update only for specific user, pass _id as well to changePrivilage and execute newPrivilages[type] = value; // update type with new value inside if condition comparing user _id.

How do you prevent a javascript object from being converted into a length 1 array of objects?

I'm working on my first solo ReactJS/Redux project and things were going well until I got to a point where I'm using an object in the Redux store that is always supposed to be a single object. When I copy the object from one part of the store (one element of the sources key) to another (the selectedItems key) that object is being stored as an array of length 1, which isn't the data I'm passing in (it's just a single object). I could live with this and just read out of that store variable as an array and just use element 0 except that when I call another method in the reducer to replace that variable in the store, that method stores the new data as a single object! My preference would be to have everything store a single object but I can't figure out how to do that. Anyway, here's some of the reducer code:
const initialState = {
sources: [
{
id: 1,
mfg: 'GE',
system: 'Smart bed',
model: '01',
name: 'GE smart bed'
},
{
id: 2,
mfg: 'IBM',
system: 'Patient monitor',
model: '03',
name: 'IBM patient monitor'
}
],
error: null,
loading: false,
purchased: false,
selectedItem: {}
};
// This is called when a user selects one of sources in the UI
// the Id of the selected sources object is passed in as action.id
// This method creates an array in state.selectedItem
const alertSourceSelect = ( state, action ) => {
let selectedItem = state.sources.filter(function (item) {
return item.id === action.id;
});
if (!selectedItem) selectedItem = {};
return {...state, selectedItem: selectedItem};
};
// When someone edits the selected source, this takes the field name and new value to
// replace in the selected source object and does so. Those values are stored in
// action.field and action.value . However, when the selected source object is updated
// it is updated as a single object and not as an array.
const selectedSourceEdit = ( state, action ) => {
return {
...state,
selectedItem: updateObject(state.selectedItem[0], { [action.field] : action.value })
};
};
const reducer = (state = initialState, action) => {
switch (action.type) {
case actionTypes.ALERT_SOURCE_SELECT: return alertSourceSelect( state, action );
case actionTypes.ALERT_SELECTED_SOURCE_EDIT: return selectedSourceEdit( state, action );
default: return state;
}
Here is the updateObject method (sorry I left it out):
export const updateObject = (oldObject, updatedProperties) => {
return {
...oldObject,
...updatedProperties
}
};
Issue : updateObject is returning object and not array,and you are maintaining selectedItem as an array not object
export const updateObject = (oldObject, updatedProperties) => {
return {
...oldObject,
...updatedProperties
}
};
Solution :
Either return array from updateObject :
export const updateObject = (oldObject, updatedProperties) => {
return [{
...oldObject,
...updatedProperties
}]
};
OR make array of returned object
const selectedSourceEdit = ( state, action ) => {
return {
...state,
selectedItem: [updateObject(state.selectedItem[0], { [action.field] : action.value })]
};
};

Reducer keep returning an empty array

I'm trying to return an array from the reducer after filling it with data, but it always returns an empty array.
export default function dashboards(state: any = dashboardsState, action: any) {
// more code
if (action.type === Types.LOAD_DASHBOARD_SUCCESS) {
// create the cards holder in the store
var cardsSkull: any = [];
Object.keys(action.payload.lists).map((idLis: any) => {
cardsSkull[idLis] = {};
console.log("still up");
});
action.payload.importedDashboards.map((impDash: any) => {
Object.keys(impDash.mappedLists).map((key: any) => {
const mpList = impDash.mappedLists[key];
cardsSkull[mpList.idlistLocal][impDash.remote_board_id] = [1, 2, 3];
console.log("still working");
});
});
console.log(cardsSkull);
// assign and ready to go
return Object.assign({}, state, {
selectedDashboardData: action.payload,
cards: cardsSkull
});
}
// more code
return state;
}
when I console.log(cardsSkull) everything looks right.
I expect the cards to have the value of cardsSkull after it is filled, but the actual output is an empty array
You define cardsSkull as array (which is an object under the hood), but because idLis is not a number, cardsSkull[idLis] = {}; does not populate an element within the array part of the object, but rather an element within the array object itself. Therefore in your screenshot, the length property of your array is still 0! Use numbers for idLis and your problem is solved.
it seems that you are assuming wrong type for cards, it is an object instead of array. I would suggest to update as following
export default function dashboards(state: any = dashboardsState, action: any) {
// more code
if (action.type === Types.LOAD_DASHBOARD_SUCCESS) {
// create the cards holder in the store
const cardsSkull = Object.keys(action.payload.lists).reduce(
(acc, idLis) => ({ ...acc, [idList]: {} }),
{}
);
action.payload.importedDashboards.forEach((impDash: any) => {
Object.keys(impDash.mappedLists).forEach((key: any) => {
const mpList = impDash.mappedLists[key];
cardsSkull[mpList.idlistLocal][impDash.remote_board_id] = [1, 2, 3];
console.log('still working');
});
});
console.log(cardsSkull);
// assign and ready to go
return {
...state,
selectedDashboardData: action.payload,
cards: cardsSkull
}
}
// more code
return state;
}

Categories

Resources