I'm building an Electron application and I'm trying to keep an array of images that are on each page so if the page is deleted I can easily delete all the associated images from the filesystem.
What I have now:
const initialState = [{
uuid: '65ec81f5-a783-4abd-bd0d-1451adda58c6',
imageUUIDs: []
}];
const actionsMap = {
[ActionTypes.ADD_IMAGE_TO_PAGE](state, action) {
const pageUUID = action.pageUUID;
const imgUUID = action.imgUUID;
return state.map(page =>
(page.uuid === pageUUID ?
Object.assign({}, page, {
imageUUIDs: page.imageUUIDs.splice(0, 0, imgUUID),
}) : page)
);
},
};
This initially seems to work when viewed at runtime, but I end up with an empty array after completion. What is the right way to maintain a list like this?
Use Array.prototype.concat instead of Array.prototype.splice. Array.prototype.concat returns a new array whereas Array.prototype.splice modifies the original array but does not return a new array, which is not what you are expecting.
Related
I need a suggestion for the below code. The objective here is to remove the specific array if the mentioned menuKey is present.
Note: sdb.menu = 'account-links' (Declared in another file);
const { menu = [] } = remainingConfig[sdb.menu]?.params || {};
const keysToRemove = ['sidebarReferAFriend'];
const filteredMenu = menu.filter(({ menuKey }: IMenuLink) => !keysToRemove.includes(menuKey));
How can I assign the filteredMenu back to remainingConfig object?
I tried with some spread operator options and it's not giving the existing same structure. So please provide some help here when you have some time.
The object structure will be like attached image.
If you can directly assign to the remainingConfig[sdb.menu].params.menu property, then since presumably you don't need to create the array if it's not there, only do the work if the array and everything leading up to it exists, then just assign back to menu:
const menuConfigParams = remainingConfig[sdb.menu]?.params;
const menu = menuConfigParams?.menu;
if (menu) {
const keysToRemove = ['sidebarReferAFriend'];
menuConfigParams.menu = menu.filter(({ menuKey }/*: IMenuLink*/) => !keysToRemove.includes(menuKey));
}
If the remainingConfig structure is deeply immutable, then we have to create a new object to replace it at every level of the nesting:
const menuConfig = remainingConfig[sdb.menu];
const menuConfigParams = menuConfig?.params;
let menu = menuConfigParams?.menu;
if (menu) {
const keysToRemove = ['sidebarReferAFriend'];
menu = menu.filter(({ menuKey }/*: IMenuLink*/) => !keysToRemove.includes(menuKey));
const newConfig = {
...remainingConfig,
[sdb.menu]: {
...menuConfig,
params: {
...menuConfig.params,
menu,
}
}
};
// ...then use whatever mechanism is in your environment to replace `remainingConfig`
// with `newConfig`...
}
Notice how at each level we're making a shallow copy of the structure via spread syntax.
I want to add another object to my exiting object but i doesn't get the value as others object have instead it gets a text, I tried a easy solution but didn't work, here is that i'm facing:
ConsoleLog Image
So instead of the key long I want to keep the numbers as they started from 0, but I don't know how?
Here is what I've tried:
const addToWatchlist = (movie) => {
const long = movies.length;
const data = {...movies, long: movie};
setMovies(movies)
ps: I'm using React.
const addToWatchlist = (movie) => {
movies.push(movie)
setMovies(movies)
I have an object of newsfeed items like below.
[{'story_id':130,'pinned':0,....},{'story_id':131,'pinned':1,....},{'story_id':132,'pinned':0,....},{'story_id':133,'pinned':0,....}]
I need to primarily order the news stories by their story_id DESC. But if a story has the property 'pinned'=1 it needs to be first.
filtered_news_feed: function() {
var list= _.orderBy(this.feed_items, ['story_id'],'desc');
return list;
},
The above works, but how do I do pinned items first, then the rest? For some reason the below completely ignores the story_id
var list= _.orderBy(this.feed_items, ['pinned','story_id'],'desc');
Using Array#sort:
const arr = [ {'story_id':130,'pinned':0}, {'story_id':131,'pinned':1}, {'story_id':132,'pinned':0}, {'story_id':133,'pinned':0} ];
const sorted = arr.sort(
({ story_id: storyIdA, pinned: pinnedA }, { story_id: storyIdB, pinned: pinnedB }) =>
pinnedB - pinnedA || storyIdB - storyIdA
);
console.log(sorted);
You can achieve this results in many ways, one of them is:
filtered_news_feed: function() {
const pinnedItems = this.feed_items.filter(item => item.pinned === 1);
const normalItems = this.feed_items.filter(item => item.pinned === 0);
return [
...pinnedItems,
_.orderBy(normalItems, ['story_id'], 'desc')
];
}
First, separate pinned items from normal items. Then return merged array with pinned items at the beginning.
Note: I used modern features of ES here. You should compile it via babel or other tool.
I'm attempting to add an object at a specific point in my 'data' array which is this components state. The following isn't working, the array simply gets emptied.
addNewBulletAfterActive = () => {
const array = this.state.data;
const newBulletPoint = {
id: this.state.data.length += 1,
title: 'Click to add'
};
const newData = array.splice(this.state.activeBulletPointId, 0, newBulletPoint);
this.setState({
data: newData
});
}
The idea is that if I have a list of 10 bullet points, the user can click on the 4th bullet point and press enter to add a new bullet point directly after. I've not had any issues adding items to the end of the array but it looks like .splice is causing issues.
I believe this should do what you're after.
function addAfter(array, index, newItem) {
return [
...array.slice(0, index),
newItem,
...array.slice(index)
];
}
This function returns a new array with a new item inserted in the middle. It doesn't mutate your original array and so will play nicely with component's state and Redux.
You can then assign the output from this function to your state.
splice returns spliced items (which is empty since you splice 0 items) and mutates original array.
const newData = array.slice(0); // copy
newData.splice(this.state.activeBulletPointId, 0, newBulletPoint);
this.setState({
data: newData
});
I think this could be an easier and faster method to do this
/*Just plain JS*/
function AddAfter(array, newObject){
array.unshift(newObject);
}
/*In react If updating state*/
var _prev = this.state.your_array; //getting the current value for the state object
var newInfo = {id: 1, more: 'This is a new object'};
_prev.unshift(newInfo);
I want to retrieve a list of products in relation to the user's position, for this I use Geofirestore and update my Flatlist
When I have my first 10 closest collections, I loop to have each of the sub-collections.
I manage to update my state well, but every time my collection is modified somewhere else, instead of updating my list, it duplicates me the object that has been modified and adds it (updated) at the end of my list and keep the old object in that list too.
For example:
const listListeningEvents = {
A: {Albert, Ducon}
B: {Mickael}
}
Another user modified 'A' and delete 'Ducon', I will get:
const listListeningEvents = {
A: {Albert, Ducon},
B: {Mickael},
A: {Albert}
}
And not:
const listListeningEvents = {
A: {Albert},
B: {Mickael},
}
That's my useEffect:
useEffect(() => {
let geoSubscriber;
let productsSubscriber;
// 1. getting user's location
getUserLocation()
// 2. then calling geoSubscriber to get the 10 nearest collections
.then((location) => geoSubscriber(location.coords))
.catch((e) => {
throw new Error(e.message);
});
//Here
geoSubscriber = async (coords) => {
let nearbyGeocollections = await geocollection
.limit(10)
.near({
center: new firestore.GeoPoint(coords.latitude, coords.longitude),
radius: 50,
})
.get();
// Empty array for loop
let nearbyUsers = [];
// 3. Getting Subcollections by looping onto the 10 collections queried by Geofirestore
productsSubscriber = await nearbyGeocollections.forEach((geo) => {
if (geo.id !== user.uid) {
firestore()
.collection("PRODUCTS")
.doc(geo.id)
.collection("USER_PRODUCTS")
.orderBy("createdDate", "desc")
.onSnapshot((product) => {
// 4. Pushing each result (and I guess the issue is here!)
nearbyUsers.push({
id: product.docs[0].id.toString(),
products: product.docs,
});
});
}
});
setLoading(false);
// 4. Setting my state which will be used within my Flatlist
setListOfProducts(nearbyUsers);
};
return () => {
if (geoSubscriber && productsSubscriber) {
geoSubscriber.remove();
productsSubscriber.remove();
}
};
}, []);
I've been struggling since ages to make this works properly and I'm going crazy.
So I'm dreaming about 2 things :
Be able to update my state without duplicating modified objects.
(Bonus) Find a way to get the 10 next nearest points when I scroll down onto my Flatlist.
In my opinion the problem is with type of nearbyUsers. It is initialized as Array =[] and when you push other object to it just add new item to at the end (array reference).
In this situation Array is not very convenient as to achieve the goal there is a need to check every existing item in the Array and find if you find one with proper id update it.
I think in this situation most convenient will be Map (Map reference). The Map indexes by the key so it is possible to just get particular value without searching it.
I will try to adjust it to presented code (not all lines, just changes):
Change type of object used to map where key is id and value is products:
let nearbyUsersMap = new Map();
Use set method instead of push to update products with particular key:
nearbyUsersMap.set(product.docs[0].id.toString(), product.docs);
Finally covert Map to Array to achieve the same object to use in further code (taken from here):
let nearbyUsers = Array.from(nearbyUsersMap, ([id, products]) => ({ id, products }));
setListOfProducts(nearbyUsers);
This should work, but I do not have any playground to test it. If you get any errors just try to resolve them. I am not very familiar with the geofirestore so I cannot help you more. For sure there are tones of other ways to achieve the goal, however this should work in the presented code and there are just few changes.