.map not is not a function on empty object? - javascript

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"]

Related

Javascript Function: Use Variable instead of single Values

I found here a script. It works fine. But now, I want to use a Variable instead of single values.
Here the original script:
const customData = {
"func":"bri",
"oid":"ID",
"onVal":1,
"offVal":0,
"...":"..."
}
const getSubset = (obj, ...keys) => keys.reduce((a, c) => ({ ...a, [c]: obj[c] }), {});
const Light.bri = getSubset(customData, "oid", "onVal", "offVal");
Result (OK):
bri: {
offVal: 0,
oid: "objekt-ID",
onVal: 1
},
Now I want to do define the keys in a variable, ideally as a object. But this do not work.
const params = {bri: "oid, onVal, offVal"};
const Light.bri = getSubset(customData, params.bri);
Result (NOK):
bri: {
oid, onVal, offVal: undefined
},
description: "Deckenspots"
}
what changes do I have to make?
Define the bri property as an array of strings. That way you can use the spread syntax (...) to pass the strings as individual arguments.
const params = {bri: ["oid", "onVal", "offVal"]}; // bri is now an array.
const Light.bri = getSubset(customData, ...params.bri); // Notice the ... before params.bri

Cannot assign to read only property with .map(). Recoil with NextJs

before I use only nextJs everything is good to go but after I try to use recoil and I try to assign new value to array object by using .map() but the error show up
Cannot assign to read only property
Here is my example Array object
const [allData, setAllData] = useRecoilState(
allDataStatte
);
Here is example state AllData
const allData = [
{
id:1,
value:"test1"
},
{
id:2,
value:"test2"
}
]
Here is my code
const edit = (listId, value) => {
allData.map((data) => {
if (data.id === listId) {
data.value = value;
}
});
};
example I want to call edit funcion like this
edit(1,"newTitle1")
I want my new allData output look like this
const data = [
{
id:1,
value:"newTitle1"
},
{
id:2,
value:"test2"
}
]
I have read someone told that I have to use .slice() to create new object but still not use how to use slice with an array object
Here is what you need to do,
const [allData, setAllData] = useRecoilState(allDataState);
const edit = (listId : number, value : string) => {
let newAllData = allData.map((data) => {
let newData = {...data};
if (data.id === listId) {
newData.value = value;
}
return newData;
});
setAllData (newAllData);
};
edit(1, 'new value 1');
Noticed, newAllData is a new array. Also newData is a new object constructed from data.
it's because of atom in recoil you have to re create object array and then setState again by using _clondeep or slice

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 })]
};
};

How to add obj to to state in my example Redux React

I have a problem with adding obj to my arr in redux store.
I want to check if some element in my arr have the same id with payload id - I don't want to push, if not push the object to array.
The initial state of the array - [] (empty)
MY REDUCER CODE:
case "UNSHIFT_COUNTRY": {
console.log("P", payload);
return {
...state,
selectedCountries: [
...state.selectedCountries,
state.selectedCountries.forEach(item => {
if (item.id !== payload.id) {
state.selectedCountries.unshift(payload);
}
})
]
};
}
PAYLOAD IS AN OBJECT
Thanks for answers!
Use find to check if your array has an object with the same id:
case "UNSHIFT_COUNTRY": {
const found = state.selectedCountries.find(country => country.id === payload.id);
return found ? state : {
...state,
selectedCountries: [...state.selectedCountries, payload]
};
}

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