I use to react-paginate package for paginate. After searching, the pagination pattern is broken. While there should be 5 items per page, this situation breaks down after the search. I share my ss and codes. thanks for your time.
here is default paginate:
and after search paginate:
and here is my code:
const displayUsers = (users, setUsers, userCurrentPage) => { // pagination configs
const startIndex = (userCurrentPage - 1) * 5
const endIndex = userCurrentPage * 5
const productsToDisplay = users.slice(startIndex, endIndex)
setUsers(productsToDisplay)
}
const handleSearch = (e) => { // filter script
let searchValue = e.target.value
let filteredTasks = users.filter((task) => {
return task.UserID.toLowerCase().includes(searchValue.toLowerCase())
})
setPaginationUsers(filteredTasks)
}
useEffect(() => {
if (searchfield === '') {
setPaginationUsers(users)
} else {
const dynamicFilter = users.filter((user) => {
return user.UserID.toLowerCase().includes(searchfield.toLowerCase())
})
setPaginationUsers(dynamicFilter)
}
}, [searchfield])
// And here is mapping area
{paginationUsers.map((userDetail, index) => {
const {
UserID,
Country,
City,
MMA,
Time,
Game,
Revenue,
Timezone,
Device_Model,
Ad_Type,
SubNetwork,
} = userDetail
if (typeof userDetail.Revenue === 'string') {
userDetail.Revenue = parseFloat(userDetail.Revenue).toFixed(6)
}
return (
<tr key={index}>
<td>{UserID}</td>
<td>{Country}</td>
<td>{City}</td>
<td>{MMA}</td>
<td>{SubNetwork}</td>
<td>{Time}</td>
<td>{Revenue}</td>
<td>{Game}</td>
<td>{Timezone}</td>
<td>{Device_Model}</td>
<td>{Ad_Type}</td>
</tr>
)
})}
Related
When I am trying to get data from an array using filter and find, it's not getting filtered also the _ids are the same when I cross-checked the array, also useState is also not updating
1. How should I filter one element from an array, Am I doing this right?
2. useState is not working, not updating data
I am getting every data from context (c1)
sd is returning array of single object, so to get one first index I am returning sd[0]
const ReadTemplate = (props) => {
const c1 = useContext(PostsContext);
const [first, myData] = useState({});
const first_load_func = () => {
const id = props.match.params.id;
const sd = c1.data.filter((c1) => id === c1._id);
const business_props = c1.business_data.filter((c1) => id === c1._id);
const startups_props = c1.startups_data.filter((c1) => id === c1._id);
const tech_props = c1.tech_data.filter((c1) => id === c1._id);
const sports_props = c1.sports_data.filter((c1) => id === c1._id);
if (sd) {
return sd[0];
} else if (business_props) {
return business_props[0];
} else if (startups_props) {
return startups_props[0];
} else if (tech_props) {
return tech_props[0];
} else if (sports_props) {
return sports_props[0];
} else {
return <MyAlert />;
}
};
const func = (data) => {
if (data) {
setTimeout(() => {
myData(data);
}, 1000);
console.log('ye first hai');
console.log(first._id);
console.log('ye data hai');
console.log(data);
} else {
console.log('No');
}
};
useEffect(() => {
first_load_func();
func(first_load_func());
}, [first]);
return (
<>
<PostDesign props={first} />
</>
);
};
export default ReadTemplate;
My guess from your code is that you should assign the filtered data when the component is rendered, not when first changes:
useEffect(() => {
func(first_load_func());
}, []);
It may be useful to convert ids toString() before comparing them:
const sd = c1.data.filter((c1) => id.toString() === c1._id.toString());
I'm creating a shopping cart app. When the user changes the quantity of an item, the price of the item should be updated along with it. However, in trying to implement this, I've encountered a bug where the items in the shopping cart are being duplicated rather than updated. Any help would be appreciated. Here is my code:
const [cart, setCart] = useState([]);
const handleQuantityChange = (e, product) => {
setCart((prevState) => [
...prevState,
...prevState.map((item) => {
if (item.id === product.id) {
return {
...item,
price: item.originalPrice * e.target.value,
quantity: e.target.value,
};
} else {
return item;
}
}),
]);
}
[...prevState, ...prevState.map()] is duplicating your list twice (one is the prevState, one is prevState.map())
You should modify your code like this
const [cart, setCart] = useState([]);
const handleQuantityChange = (e, product) => {
setCart((prevState) => [
...prevState.map((item) => {
if (item.id === product.id) {
return {
...item,
price: item.originalPrice * e.target.value,
quantity: e.target.value,
};
} else {
return item;
}
}),
]);
}
Another way without prevState but cart state
const [cart, setCart] = useState([]);
const handleQuantityChange = (e, product) => {
const updatedCart = cart.map((item) => {
if (item.id === product.id) {
return {
...item,
price: item.originalPrice * e.target.value,
quantity: e.target.value,
};
} else {
return item;
}
});
setCart(updatedCart);
}
[...prevState, ...prevState.map()] is duplicated one.
You can find the corresponding item in prevState by find function and update its price and quantity.
You can update setCart function call like the following.
setCart(prevState => {
const newState = prevState? [...prevState] : [];
const item = newState.find(x => x.id === product.id);
let qty = parseFloat(e.target.value);
qty = isNaN(qty) ? 0 : qty;
item.price = item.originalPrice * qty;
item.quantity = qty;
return newState;
});
My goal is to use the button on the page to open a websocket connection, subscribe to the ticker feed, then update each list item's price based on the ID of the list item. Currently I have a list that maps through the initial API call's response and saves each object's ID to an array, which in turn is used to build a <li> for each ID. This creates 96 list items. I have also gotten the price to update live via a <p> element in each <li>.
I am having trouble targeting the price for just the matching row ID to the incoming data object's ID so that only that matching row is re-rendered when it gets a match. Below is my code:
ProductRow.js
import React from 'react';
export default function ProductRow(props) {
return <li key={props.id}><p>{ props.id }</p><p>{props.price}</p></li>;
}
WatchList.js
import React, { useState, useEffect, useRef } from "react";
import { Button } from 'react-bootstrap';
import ProductRow from "./ProductRow";
export default function WatchList() {
const [currencies, setcurrencies] = useState([]);
const product_ids = currencies.map((cur) => cur.id);
const [price, setprice] = useState("0.00");
const [isToggle, setToggle] = useState();
const ws = useRef(null);
let first = useRef(false);
const url = "https://api.pro.coinbase.com";
useEffect(() => {
ws.current = new WebSocket("wss://ws-feed.pro.coinbase.com");
let pairs = [];
const apiCall = async () => {
await fetch(url + "/products")
.then((res) => res.json())
.then((data) => (pairs = data));
let filtered = pairs.filter((pair) => {
if (pair.quote_currency === "USD") {
return pair;
}
});
filtered = filtered.sort((a, b) => {
if (a.base_currency < b.base_currency) {
return -1;
}
if (a.base_currency > b.base_currency) {
return 1;
}
return 0;
});
setcurrencies(filtered);
first.current = true;
};
apiCall();
}, []);
useEffect(() => {
ws.current.onmessage = (e) => {
if (!first.current) {
return;
}
let data = JSON.parse(e.data);
if (data.type !== "ticker") {
return;
}
setprice(data.price);
console.log(data.product_id, price);
};
}, [price]);
const handleToggleClick = (e) => {
if (!isToggle) {
let msg = {
type: "subscribe",
product_ids: product_ids,
channels: ["ticker"]
};
let jsonMsg = JSON.stringify(msg);
ws.current.send(jsonMsg);
setToggle(true);
console.log('Toggled On');
}
else {
let unsubMsg = {
type: "unsubscribe",
product_ids: product_ids,
channels: ["ticker"]
};
let unsub = JSON.stringify(unsubMsg);
ws.current.send(unsub);
setToggle(false);
console.log('Toggled Off');
}
};
return (
<div className="container">
<Button onClick={handleToggleClick}><p className="mb-0">Toggle</p></Button>
<ul>
{currencies.map((cur) => {
return <ProductRow id={cur.id} price={price}></ProductRow>
})}
</ul>
</div>
);
}
App.js
import React from "react";
import WatchList from "./components/Watchlist";
import "./scss/App.scss";
export default class App extends React.Component {
render() {
return (
<WatchList></WatchList>
)
}
}
Initialize the price state to be an empty object i.e. {}. We'll refer the price values by the the product_id on getting the response from websocket
// Initialize to empty object
const [price, setprice] = useState({});
...
// Refer and update/add the price by the product_id
useEffect(() => {
ws.current.onmessage = (e) => {
if (!first.current) {
return;
}
let data = JSON.parse(e.data);
if (data.type !== "ticker") {
return;
}
// setprice(data.price)
setprice(prev => ({ ...prev, [data.product_id]: data.price}));
console.log(data.product_id, price);
};
}, [price]);
Render your ProductRows as
<ul>
{currencies.map((cur) => {
return <ProductRow key={cur.id} id={cur.id} price={price[cur.id]}></ProductRow>
})}
</ul>
You don't have to manage anykind of sorting or searching for the relevant prices for products.
I'm using the grid api to get the selected rows by using the function getSelectedRows(). However, the list of rows seems to be unordered, i.e the items are not in the order I selected them in.
Is there another way to get the selected rows in the order they were selected?
You can keep track of the selected items yourself and make sure it's chronologically ordered by listening to selectionChanged event.
// global keyboard state, put this outside of the function body
// we need to store the current shift key state to know if user
// are selecting multiple rows
const KEYBOARD_STATE = {
isShiftPressed: false
};
document.addEventListener("keydown", (e) => {
KEYBOARD_STATE.isShiftPressed = e.key === "Shift";
});
document.addEventListener("keyup", (e) => {
KEYBOARD_STATE.isShiftPressed = false;
});
const [selection, setSelection] = React.useState([]);
const onSelectionChanged = (e) => {
const selectedNodes = e.api.getSelectedNodes();
const lastSelectedNode =
selectedNodes[0]?.selectionController?.lastSelectedNode;
// if lastSelectedNode is missing while multi-selecting,
// AgGrid will select from the first row
const selectedNodeFrom = lastSelectedNode || e.api.getRenderedNodes()[0];
const isRangeSelect = KEYBOARD_STATE.isShiftPressed;
const difference = (arr1, arr2) => arr1.filter((x) => !arr2.includes(x));
const newSelection = difference(selectedNodes, selection);
if (newSelection.length > 0) {
if (isRangeSelect) {
const isSelectBackward =
newSelection[0].rowIndex < selectedNodeFrom.rowIndex;
if (isSelectBackward) {
newSelection.reverse();
}
}
newSelection.forEach((n) => updateSelection(n));
} else {
updateSelection(); // deselect
}
};
const updateSelection = (rowNode) => {
setSelection((selections) => {
if (rowNode) {
const isSelected = rowNode.isSelected();
if (isSelected) {
return [...selections, rowNode];
} else {
return selections.filter((s) => s.id !== rowNode.id);
}
} else {
return selections.filter((n) => n.isSelected());
}
});
};
return (
<>
<pre>
{JSON.stringify(selection.map((n) => n.data.id))}
</pre>
<AgGridReact
rowSelection="multiple"
columnDefs={columnDefs}
rowMultiSelectWithClick
onSelectionChanged={onSelectionChanged}
{...}
/>
</>
);
Live Demo
I'm building a product catalog with gatsby and firebase, and I want to display a list of products
according to the product category that the user chooses. I'd fetch all products add pagination and now I need a filter menu or select, so I tried this to implement a filter..before that everything was going fine...
imports
...
// query
export const data = graphql`
query data($skip:Int!, $limit:Int!) {
products: allProducts(
skip: $skip,
limit: $limit,
sort: {fields: id, order: ASC}) {
edges {
node {
id
slug
categories
model
previewImg
description
category
}
}
}
}
`
//component
class ProductsSectionTemplate extends Component {
constructor(props){
super(props)
this.state={
products:[],
product:''
}
}
handleChange = event => {
this.setState({ value: event.target.value });
};
handleChangeProduct = event => {
this.setState({ product: event.target.value });
};
getUnique(arr, comp) {
const unique = arr
//store the comparison values in array
.map(e => e[comp])
// store the keys of the unique objects
.map((e, i, final) => final.indexOf(e) === i && i)
// eliminate the dead keys & store unique objects
.filter(e => arr[e])
.map(e => arr[e]);
return unique;
}
componentDidMount(){
const products = data.products.edges.map( product => ({
...product.node,
previewImg: product.node.previewImg,
category:product.node.category
}))
this.setState({
products: products
})
}
render(){
const { pageContext} = this.props
const products = this.state.products
const product = this.state.product
const { currentPage, numPages } = pageContext
const isFirst = currentPage === 1
const isLast = currentPage === numPages
const prevPage = currentPage - 1 === 1 ? "/" : (currentPage - 1).toString()
const nextPage = (currentPage + 1).toString()
const uniqueProduct = this.getUnique(this.state.products, "category");
const filterDropdown = products.filter( result => result.category === product );
return(
<Layout>
<h1>Productos</h1>
<select
value={this.state.product}
onChange={this.handleChangeProduct}
>
{uniqueProduct.map(product => (
<option key={product.id} value={product.category}>{product.category}</option>
))}
</select>
<ProductsSection products={filterDropdown}/>
{!isFirst && (
<Link to={`/products/${prevPage}`} rel="prev">
← Previous Page
</Link>
)}
{Array.from({ length: numPages }, (_, i) => (
<Link key={`pagination-number${i + 1}`} to={`/products/${i === 0 ? "" : i + 1}`}>
{i + 1}
</Link>
))}
{!isLast && (
<Link to={`/products/${nextPage}`} rel="next">
Next Page →
</Link>
)}
</Layout>
)
}
}
...
what I get of this is an error that says:
TypeError: Cannot read property 'edges' of undefined
ProductsSectionTemplate.componentDidMount
}
59 | componentDidMount(){
> 60 | const products = data.products.edges.map( product => ({
61 | ...product.node,
62 | previewImg: product.node.previewImg,
63 | category:product.node.category
here is the gatsby-node.js file:
const path = require('path')
exports.createPages = async ({graphql, actions}) => {
const { createPage } = actions
const products = await graphql(`
{
allProducts (sort: {fields: id, order: ASC}, limit: 100){
edges {
node {
id
slug
model
description
categories
}
}
}
}
`).then(result => {
if (result.errors) throw result.errors;
const productNodes = result.data.allProducts.edges;
return productNodes.map( edge =>{
return {
...edge.node
}
})
})
const productsPerPage = 6
const numPages = Math.ceil(products.length / productsPerPage);
Array.from({length:numPages}).forEach((_, i)=>{
createPage({
path: i === 0 ? '/products' : `/products/${i + 1}`,
component: path.resolve('./src/templates/ProductsSectionTemplate.js'),
context: {
products,
limit:productsPerPage,
skip: i * productsPerPage,
numPages,
currentPage: i + 1,
}
});
})
products.forEach( product => {
createPage({
path: `/${product.slug}`,
component: path.resolve('./src/templates/singleProduct.js'),
context: {
product
}
});
});
}
can anybody help me to get this working right..?
Thanks in advice, regards
One reason your query might come back as undefined could be that your graphQL variables do not contain any values.
You can only use variables inside your graphQL with page queries. For this you need to define context variables inside your gatsby-node.js as documented in the official documentation:
posts.forEach(({ node }, index) => {
createPage({
path: node.fields.slug,
component: path.resolve(`./src/templates/blog-post.js`),
// values in the context object are passed in as variables to page queries
context: {
title: node.passThisVariable,
},
})
})
If this does not answer your question, edit your question with your gatsby-node.js code.
Solved using hooks:
const ProductsSectionTemplate = ({ data }) => {
const [products, setProducts ] = useState([])
const [product, setProduct ] = useState('')
function handleChangeProduct (e) {
setProduct(e.target.value);
};
function getUnique(arr, comp) {
const unique = arr
//store the comparison values in array
.map(e => e[comp])
// store the keys of the unique objects
.map((e, i, final) => final.indexOf(e) === i && i)
// eliminate the dead keys & store unique objects
.filter(e => arr[e])
.map(e => arr[e]);
return unique;
}
useEffect(()=>{
const productsList = data.products.edges.map( product => ({
...product.node,
previewImg: product.node.previewImg,
category:product.node.category,
categories:product.node.categories
}))
setProducts(productsList)
},[data])
const uniqueProduct = getUnique(products, 'category')
const filterDropdown = products.filter(result => result.category === product)
return(
<Layout>
<h1>Productos</h1>
<h4 className="title">Filtrar Productos:</h4>
<div className="filters">
{uniqueProduct.map(product => (
<label key={product.id}>
<input
className='filters-available-size'
type="checkbox"
value={product.category}
onChange={handleChangeProduct}
/>
<span className="checkmark">
{product.category}
</span>
</label>
))}
</div>
{!!filterDropdown.length && (
<div>
<p>{product}</p>
<ProductsSection products={filterDropdown}/>
</div>
)}
{!!products.length && !filterDropdown.length && (
<div>
<p>Categorias</p>
<ProductsSection products={uniqueProduct}/>
</div>
)}
</Layout>
)
}
and also changed the query to just:
export const data = graphql`
{
products: allProducts{
edges {
node {
id
slug
categories
model
previewImg
description
category
}
}
}
}
`