I have created this Array:
let products = {
data: [
{
productName: "Product1",
},
{
productName: "Product2",
},
{
productName: "Product3",
},
{
productName: "Product4",
},
{
productName: "Product5",
},
{
multiple other products
},
],
};
I want to loop through and display all of the objects in this Array. However, after 10 objects, I want the objects to move onto another page.
The page should display the first 10 objects within this Array. There should be a button the user can click to view the next 10 products. When the user clicks this button, the next 10 products should then be shown.
I want to loop through the objects, rather than manually add each of these pages.
However, all of these pages should be displayed using a single HTML, CSS and JavaScript file.
Buttons should be used in order to allow the user to switch between these pages.
Related
Let's say I am building a shopping list app. I have the ability to create different shopping lists. I have three screens:
-- Shopping Lists: displays all the lists
---- List Details: displays all the items from a list
------ List Item Details: displays all the info about an item
To store the state and avoid prop drilling I use Context. My state could look like:
shoppingLists = [
{
title: 'Groceries',
items: [{
name: 'Apples',
quantity: 3
... (other info)
},
items: [{
name: 'Oranges',
quantity: 6,
...
}]
},
{
title: 'Office Supplies',
items: [{
name: 'Paper',
quantity: 2
... (other info)
},
items: [{
name: 'Pens',
quantity: 25,
...
}]
}]
When I tap on a Shopping List on the Shopping Lists screen I do
navigation.navigate('ListDetails', {params: listItem})
In the List Details screen I have de ability to change the quantity of an item or delete them. If I do any of this actions I have to make an API call to my server to update the value on the database. Here are my questions:
Currently I store the values in a local variable in my screen for example:
const [title, setTitle] = useState(props.route.params.title)
const [items, setItems] = useState(prop.route.params.items)
And if I make a change in the quantity I use setState to update my local array and then make an API call to update the context. This results problematic when adding more nested screens.
For example if I would give the user the ability to change the item quantity in the List Item Details screen, when the user goes back to the List Details screen, the values would not be updated.
My question is, which is the correct way to grab the state of the context and update it locally?
For example should I do something like:
navigation.navigate('ListDetails', {params: { listName: 'Groceries' })
And then in my List Details screen grab the correct list from the array like:
const {lists} = useContext(ShoppingLists)
const list = lists.filter(l => l.title === props.route.params.title)
What is the correct way?
The other question I have is a more general question. I want to use optimistic responses: when the user updates the quantity of an item in the list I update it locally and send the request to the server. If there's an error rollback the change. Which would be the correct way of doing this?
Thanks!
I would advise against updating context data in such a way. You could create a setList() method in the context instead, or updateList() to aggregate new data to the existing data.
This is related to the previous one. You could wrap the logic of POSTing to the server in a try-catch block and throw an error when it's not successful. Then you can set the new value only when it's successful. Another option would be to return the promise, so you could handle errors from outside, like setList().then(response => {}).catch(error => {}) though I don't think this looks that good.
Think you're over complicating it and also in your list you're not showing an id for each item. You should build your database with all the items and their unique id then call upon that when needed. The id should never change and that's easier to pass around and reference.
For example you can build an object in context with just the id and quantity and use useReducer for this:
https://reactjs.org/docs/hooks-reference.html#usereducer
I am using react-select to render the dropdown. The options to render the dropdown looks like this
[
{
text:'Fruit',
value:'mango'
level: 0
},
{
text:'Seasonal',
slug: 'saasonal',
level: 1
},
{
text:'Orange',
slug: 'orange',
level: 2
},
{
text:'Mango',
slug: 'mango',
level: 2
},
{
text: 'Winter',
slug:'winter',
level:1
},
{
text: 'Plum',
slug:'plum',
level:2
}
]
I would like the dropdown to be like
Fruit
Seasonal
Orange
Mango
Winter
Plum
I have tried adding a group to the react-select, but then the group heading is not clickable.
I have also referred to the stackoverflow link
[https://stackoverflow.com/questions/53119912/how-can-i-create-nested-option-groups-in-react-select-v2][1]
and tried creating a recursive dropdown in the same manner it is posted on the link above by passing my options as the data but was not successful.
The order of the within nested dropdown is based on the level.
react-select actually just got this feature builtin in July.
Here's the pull request where they implemented it.
Here's a working example from the pull request page.
I'm not sure if it has made its way into the master branch yet or not but you can always pull from the version listed in the package.json file in the sample above if the sample code doesn't work with the version you're using.
EDIT: Scratch that, you want group headings to be clickable. I don't think that was part of this commit.
I'm fairly new to Gatsby and React and I couldn't find an answer to my problem.
I want to be able to have filtering options on the home of my website that allow the user to display only content relevant to that filter.
Let's say my posts are recipes and they are categorized by type: main, snack and dessert.
I want a filter, can be a button or a drop-down it doesn't matter, and when the user selects it I will display only the items relevant. Ideally I'm going to have multiple filters, around 4-5 for different properties of the frontmatter of my posts .
From what I understand it's not really something I can do with graphql because after build I cannot access it anymore so I was seeking some advice from more experienced devs.
If you have a small set of posts, I think you can make a search component that get all the posts & then use something like js-search or flexsearch to index them.
In a non-page component (not in src/pages folder), you can use StaticQuery to get all the posts' info.
Say you have this graphql query result:
data: {
allMarkdownRemark: {
edges: [{
node: {
id: '1234-1233...',
fields: {
slug: '/hello/'
},
frontmatter: {
title: 'hello',
tags: [ 'go', 'js' ]
}
}
}, {
node: {
id: ...
}
}]
}
}
Then you can index & search for post, say, with js-search:
const posts = data.allMarkdownRemark.edges.map(({ node }) => node) // unwrap edges
const postIndex = new JsSearch.Search('id')
postIndex.addIndex(['frontmatter', 'tags']) // index node.frontmatter.tags
postIndex.addIndex(['frontmatter', 'title'])
postIndex.addDocuments(posts) // add data to array
const results = postIndex.search('go')
console.log(results) // [{ id: '1234-1233...', frontmatter: { title: 'hello', tags: [ 'go', 'js' ]}}]
Then you can store this result in, say, the component's state & render the results as posts.
Gatsby's doc also has a guide on adding search to your site, though I think the js-search part is a bit overwhelming.
I have a object which kind of looks like this:
{
data: [
{
id: 28,
type: "blabla",
name: "myname",
language: "en",
active: true
},
{
id: 5,
type: "blabla",
name: "myname2",
language: "fr",
active: false
},
// etc
]
}
I have split this object up into groups which I am display like this:
<li class="suggestion" v-for="suggestion in group">
</li>
I want to highlight my results so that is why I have a position property on my Vue object. which can be changed.
I have a watcher set up for the position attribute:
position() {
this.suggestions.forEach((suggestion, index) => {
suggestion.active = index === this.position;
});
}
It will make the current position(so the currently item active). This works fine when I am checking the array of objects and their properties. The items change their .active property perfectly. But the class binding does not seem to re-evaluate.
What is going wrong here? The initial active state does get taken into account and my first item is highlighted perfectly fine.
Nothing happens on a change to the actual classes though yet with the Vue devtools I can see perfectly fine that the objects properties are changing.
So the problem was that if object gets created like this:
object[suggestion.type].push(suggestion);
Vue doesn't detect changes to that object. It has to do with how Vue watches objects for changes.
In order for Vue to play nicely with objects you create and want to be reactive you need to utilize Vue.set
Vue.set(object, suggestion.type, suggestion)
Or
this.$set(object, suggestion.type, suggestion)
Let's say I've got CouchDB documents in the following format:
...
{
player: 'abcde',
action: 'run'
},
{
player: 'abcde',
action: 'jump'
},
{
player: 'abcde',
action: 'left'
},
{
player: 'abcde',
action: 'right'
},
....
My view looks like this:
function(doc) {
emit(doc.player, doc.action)
}
How can I count how many times player abcde has an action jump immediately followed by action run? I don't want the total number of jumps and runs. It is even possible to access previous or next documents from the current one inside a map or reduce function?
Thank you!
No, you can't access other documents in a map/reduce like that. For starters I don't think reduce order is explicitly defined, so 'previous' and 'next' aren't even really meaningful I'm afraid.
Instead I'd suggest you collapse the whole history of each players actions into a single document like:
{
"player": "abcde",
"actions" : [ "right", "run", "jump" ]
}
You can then count specific sets of ordered actions from the array in your map method alone, and trivially aggregate them as desired in your reduce.