I am just trying to figure out what is the issue with sorting this date property from most recent to oldest. For some reason, I am not getting the sort order correctly in the next.js app. Here is what the array containing it looks like. It is an array of objects.
And in each of these objects, theres a record_date property:
For some reason, it is not sorting it at all. Here is my code:
return {
props: {
pageData,
headerData,
footerData,
hydrationData: {
productStore: {
products: cleanedProducts.sort(
(a, b) =>
new Date(a.record_date).valueOf() -
new Date(b.record_date).valueOf(),
),
filterCategories: filterCategories,
filterOptions: filterOptions,
},
It just seems like none of the sorting is being applied. Not sure if its a caching issue in nextjs or just something with the sort.
I have also tried:
products: cleanedProducts.sort(
(a, b) =>
new Date(a.record_date).getDate() -
new Date(b.record_date).getDate(),
)
Related
I am a newbie learning React Native.
I have still struggled to show (returning) elements through mapping.
The code I have written is attached at the very bottom.
So, I fetched object data from Firestore and would like to map through it. The first problem was that I couldn't map through an object in js, but I solved it by extracting keys in a list. But the second problem happened, which elements couldn't be used and the screen was blank.
Here is the code.
The two console.log are working correctly and showing a single ride info in the terminal, but I don't know what to write below that.
This is just an example of data of rides shown in the console.
The format of "rides" data is kind of complicated which is separated by date so something like below. I have been thinking of the data format too while fetching the data.
{
dateFormat: [{obj}, {obj}, {obj}],
dateFormat: [{obj}, {obj}, {obj}],
dateFormat: [{obj}, {obj}, {obj}]
},
export const HomeScreen = ({ navigation }) => {
const { fetchRides, rides } =
useFirestoreContext();
useEffect(() => {
fetchRides();
return;
// await currUserExists();
}, []);
return Object.keys(rides).length > 0 ? (
Object.keys(rides).map((key) => {
console.log(key);
rides[key].map((ride, i) => {
console.log({ ride });
return <Text>{ride.boardType}</Text>;
});
})
) : (
<Text>Loading...</Text>
);
};
I'm trying to make a filter based on a Strapi relation.
My Strapi response looks like this:
I'm using Next Js for the frontend, so I assign props like so:
return {
props: {
projects: data.projects.data,
categories: categoriesData.data.categories.data,
},
}
I map through all of the project and list them all as cards. Then I want to filter them based on a button click. The buttons are the categories names and I map over that array as well. On click of each button I run a function called "handleProjects" and this is where I run into an issue.
I have previously made a filter using SanityCMS and Next Js, however, the code structure of the response in Sanity is much clearer compared to that of Strapi.
This is the code I've used in my previous project with Sanity:
const [filteredProducts, setFilteredProducts] = useState(products)
function handleProducts(e) {
let categoryType = e.target.value
setFilteredProducts(
products.filter((product) => product.category == categoryType)
)
}
I'm using this query where I alias the category as such and it is much simpler:
const productQuery = `*[_type == "product"] {
_id,
slug,
name,
image,
"category": category->name
}`
My function for my Strapi project looks like this:
function handleProjects(e) {
let categoryType = e.target.value
setFilteredProjects(
projects.filter((project) =>
project.attributes.categories.data.map((i) =>
i.attributes.title.includes(categoryType)
)
)
)
}
I'm having an array of objects, but at some point I have to map over an array of objects one level deeper and see if the categoryType matches some of the object values two levels deep.
Can anyone show me what I'm doing wrong here?
In my Vue application, I have Vuex store modules with large arrays of resource objects in their state. To easily access individual resources in those arrays, I make Vuex getter functions that map resources or lists of resources to various keys (e.g. 'id' or 'tags'). This leads to sluggish performance and a huge memory memory footprint. How do I get the same functionality and reactivity without so much duplicated data?
Store Module Example
export default {
state: () => ({
all: [
{ id: 1, tags: ['tag1', 'tag2'] },
...
],
...
}),
...
getters: {
byId: (state) => {
return state.all.reduce((map, item) => {
map[item.id] = item
return map
}, {})
},
byTag: (state) => {
return state.all.reduce((map, item, index) => {
for (let i = 0; i < item.tags.length; i++) {
map[item.tags[i]] = map[item.tags[i]] || []
map[item.tags[i]].push(item)
}
return map
}, {})
},
}
}
Component Example
export default {
...,
data () {
return {
itemId: 1
}
},
computed: {
item () {
return this.$store.getters['path/to/byId'][this.itemId]
},
relatedItems () {
return this.item && this.item.tags.length
? this.$store.getters['path/to/byTag'][this.item.tags[0]]
: []
}
}
}
To fix this problem, look to an old, standard practice in programming: indexing. Instead of storing a map with the full item values duplicated in the getter, you can store a map to the index of the item in state.all. Then, you can create a new getter that returns a function to access a single item. In my experience, the indexing getter functions always run faster than the old getter functions, and their output takes up a lot less space in memory (on average 80% less in my app).
New Store Module Example
export default {
state: () => ({
all: [
{ id: 1, tags: ['tag1', 'tag2'] },
...
],
...
}),
...
getters: {
indexById: (state) => {
return state.all.reduce((map, item, index) => {
// Store the `index` instead of the `item`
map[item.id] = index
return map
}, {})
},
byId: (state, getters) => (id) => {
return state.all[getters.indexById[id]]
},
indexByTags: (state) => {
return state.all.reduce((map, item, index) => {
for (let i = 0; i < item.tags.length; i++) {
map[item.tags[i]] = map[item.tags[i]] || []
// Again, store the `index` not the `item`
map[item.tags[i]].push(index)
}
return map
}, {})
},
byTag: (state, getters) => (tag) => {
return (getters.indexByTags[tag] || []).map(index => state.all[index])
}
}
}
New Component Example
export default {
...,
data () {
return {
itemId: 1
}
},
computed: {
item () {
return this.$store.getters['path/to/byId'](this.itemId)
},
relatedItems () {
return this.item && this.item.tags.length
? this.$store.getters['path/to/byTag'](this.item.tags[0])
: []
}
}
}
The change seems small, but it makes a huge difference in terms of performance and memory efficiency. It is still fully reactive, just as before, but you're no longer duplicating all of the resource objects in memory. In my implementation, I abstracted out the various indexing methodologies and index expansion methodologies to make the code very maintainable.
You can check out a full proof of concept on github, here: https://github.com/aidangarza/vuex-indexed-getters
While I agree with #aidangarza, I think your biggest issue is the reactivity. Specifically the computed property. This adds a lot of bloated logic and slow code that listens for everything - something you don't need.
Finding the related items will always lead you to looping through the whole list - there's no easy way around it. BUT it will be much faster if you call this by yourself.
What I mean is that computed properties are about something that is going to be computed. You are actually filtering your results. Put a watcher on your variables, and then call the getters by yourself. Something along the lines (semi-code):
watch: {
itemId() {
this.item = this.$store.getters['path/to/byId'][this.itemId]
}
}
You can test with item first and if it works better (which I believe it will) - add watcher for the more complex tags.
Good luck!
While only storing select fields is a good intermediate option (per #aidangarza), it's still not viable when you end up with really huge sets of data. E.g. actively working with 2 million records of "just 2 fields" will still eat your memory and ruin browser performance.
In general, when working with large (or unpredictable) data sets in Vue (using VueX), simply skip the get and commit mechanisms altogether. Keep using VueX to centralize your CRUD operations (via Actions), but do not try to "cache" the results, rather let each component cache what they need for as long as they're using it (e.g. the current working page of the results, some projection thereof, etc.).
In my experience VueX caching is intended for reasonably bounded data, or bounded subsets of data in the current usage context (i.e. for a currently logged in user). When you have data where you have no idea about its scale, then keep its access on an "as needed" basis by your Vue components via Actions only; no getters or mutations for those potentially huge data sets.
confusing title let me explain.
I have an array of categories and array of products.
the array of products is an array of objects, one of the keys is categories, which itself is an array of objects and one of the keys im interested in is title.
the array of categories is an array of objects too.
I want to filter the products array to return me just the products for my chosen category (which is set in state)
I've got this, however it does not work:
filterCategories = () => {
return this.state.products.filter((product => {
return product.categories.map((cat) => {
cat.title == this.state.chosenCategory
})
}))
}
this method seems like it should. to my knowledge, im filtering the products array by mapping over each product and then mapping over that products categories and checking if the category title is equal to the title in state. clearly I've gone wrong somewhere. can anyone see it?
sample data:
products = [
{
id: '123',
title: 'wine',
categories: [
{title: 'drinks'}
]
}
]
categories = [
{
id: '123',
title: 'drinks'
}
]
It looks like you want to test whether any of the category titles match the chosenCategory: so, use the some method. Also, even better, if you're sure there's exactly one matching category, use .find instead of filter. Also make sure to return a value at the end of the internal function (which you aren't doing currently), or use an arrow function with implicit return:
filterCategories = () => (
this.state.products.find((product) => (
product.categories.some(({ title }) => (
title === this.state.chosenCategory
))
))
)
Filter callback function is a predicate, to test each element of the array. you are not returning anything from the inner map function too, you must instead have a filter there like
filterCategories = () => {
return this.state.products.filter((product => {
return product.categories.filter((cat) => {
return cat.title == this.state.chosenCategory
})
}))
}
I Need help regarding an SQL result to be converted into an array of objects.
SQL returns results with these columns in JSON format:
po_no
po_line_no
material_no
material_name
po_qty
grpo_qty
These should be nested into:
po_no,
lines: {
po_line_no,
material_no,
material_name,
po_qty,
items: {
grpo_qty
}
}
However, I don't know how to nest 3 or more levels deep using ES6.
I was using this code before,
Object.values(data.reduce((r, {column1,column2, column3, column4}) => {
r[column1] = r[column1] || {column1, column2_items}
r[column1].column2_items.push({ column2: column2 })
}))
But I don't know how to nest it deeper.