Push specific object into list using id React - javascript

I got a list of objects which im displaying on the screen with the help of .map function.
It looks like this:
Component 1:
let itemList = [
{
type: "White T-shirt",
id: 1,
cost: 300,
image: whiteTshirt
},
{
type: "Purple T-shirt",
id: 2,
cost: 350,
image: purpleTshirt
},
{
type: "Baseballcap",
id: 3,
cost: 150,
image: whiteCap
},
{
type: "Vice Golfball",
id: 4,
cost: 40,
image: golfball
},
{
type: "Mousepad",
id: 5,
cost: 200,
image: mousepad
}
];
let products = itemList.map(items => {
let item =
<div key={items.id}>
<h2>{items.type}</h2>
<img className="image" src={items.image}></img>
<p className="price">${items.cost}</p>
<button onClick={onBuy} className="buy-btn">Buy</button>
</div>
return item;
})
return(
{shoppingcart ? <Component2 /> : null}
<main> {products} </main>
)
Component 2:
const Comopnent2 = props => {
const [webshop, setWebshop] = useState(false);
return(
<div>
{webshop ? <Webshop /> : null }
<a href="/Webshop" onClick={e => { e.preventDefault(); setWebshop(true)}} >
<p className="to-shop"> Back to shop</p></a>
<h2 className="shopping-header">Your Shopping Cart</h2>
<div className="cart-container">
// Here i want to object that i clicked display
</div>
)
}
What i want is to push one specific object to another array in another component that i have. I want to do that when i click the button which calls the onBuy funcion. How do i manage that? Thanks.

First create a hook for the cart item inside component 1:
const [cartItem, setCartItem] = useState();
set cartItem whenever the button is clicked and onBuy is called:
onBuy (id) {
let checkoutItem = this.itemList.find(item => item.id === id)
setCartItem(checkoutItem)
}
You'll be required to pass item id when you declare the button which call onBuy function.
let products = itemList.map(items => {
let item =
<div key={items.id}>
<h2>{items.type}</h2>
<img className="image" src={items.image}></img>
<p className="price">${items.cost}</p>
<button onClick={onBuy(item.id)} className="buy-btn">Buy</button>
</div>
return item;
})
To pass this selection to component 2. You can pass it as a prop in component 1:
return(
{shoppingcart ? <Component2 item={cartItem} /> : null}
<main> {products} </main>
In the component 2 You can display the data accordingly from props:
const Comopnent2 = props => {
const [webshop, setWebshop] = useState(false);
return(
<div>
{webshop ? <Webshop /> : null }
<a href="/Webshop" onClick={e => { e.preventDefault(); setWebshop(true)}} >
<p className="to-shop"> Back to shop</p></a>
<h2 className="shopping-header">Your Shopping Cart</h2>
<div className="cart-container">
{prop.item.name} //whatever properties your cart item has, I have used name just for example
</div>
)
}

Related

Getting Undefined while accessing the values of data object inside map in Next.js

// while accessing the object values from data, I'm getting undefined in map
// ../data/section1
const data = [{
id: 1,
image: './images/homepage/xbox-games.png',
text: 'Buy Xbox games and consoles',
}, {
id: 2,
image: './images/homepage/shop_surface_devices.webp',
text: 'Shop surface devices',
}, {
id: 3,
image: './images/homepage/choose_your_ms_365.png',
text: 'Choose your Microsoft 365',
}, {
id: 4,
image: './images/homepage/shop_windows_10.png',
text: 'Shop Windows 10',
}]
export default data;
// the actual component
import data from "../data/section1";
const Section1 = () => {
return (
<>
<div class="mx-20">
{data.map((vals) => {
<div class="">
<img src={vals.image}/>
<p>{vals.text}</p>
</div>
})}
</div>
</>
)
}
export default Section1;
return JSX from the map
import data from "../data/section1";
const Section1 = () => {
return (
<>
<div class="mx-20">
{data.map((vals) => {
return (
<div class="">
<img src={vals.image}/>
<p>{vals.text}</p>
</div>
)
})}
</div>
</>
)
}
export default Section1;
I had the same problem, then tried the first bracket instead of the second, and it resolved the problem
import data from "../data/section1";
const Section1 = () => {
return (
<>
<div class="mx-20">
{data.map((vals) => (
<div class="">
<img src={vals.image}/>
<p>{vals.text}</p>
</div>
))}
</div>
</>
)
}
export default Section1;

This filter method is working in console but not in ui in react

I want to filter items by filter method and I did it but it doesn't work in UI but
when I log it inside console it's working properly
I don't know where is the problem I put 2 images
Explanation of this code:
Looping inside currencies_info by map method and show them when I click on it and this completely working then I want filter the list when user enter input inside it I use filter method and this completely working in console not in UI
import React, { useState } from "react";
// Artificial object about currencies information
let currencies_info = [
{
id: 1,
name: "بیت کوین (bitcoin)",
icon: "images/crypto-logos/bitcoin.png",
world_price: 39309.13,
website_price: "3000",
balance: 0,
in_tomans: 0
},
{
id: 2,
name: "اتریوم (ethereum)",
icon: "images/crypto-logos/ethereum.png",
world_price: 39309.13,
website_price: "90",
balance: 0,
in_tomans: 0
},
{
id: 3,
name: "تتر (tether)",
icon: "images/crypto-logos/tether.png",
world_price: 39309.13,
website_price: "5",
balance: 0,
in_tomans: 0
},
{
id: 4,
name: "دوج کوین (dogecoin)",
icon: "images/crypto-logos/dogecoin.png",
world_price: 39309.13,
website_price: "1000000",
balance: 0,
in_tomans: 0
},
{
id: 5,
name: "ریپل (ripple)",
icon: "images/crypto-logos/xrp.png",
world_price: 39309.13,
website_price: "1,108",
balance: 0,
in_tomans: 0
}
];
export default function Buy() {
// States
let [api_data, set_api_data] = useState(currencies_info);
const [currency_icon, set_currency_icon] = useState("");
const [currency_name, set_currency_name] = useState("");
const [currency_price, set_currency_price] = useState(0);
const [dropdown, set_drop_down] = useState(false);
let [search_filter, set_search_filter] = useState("");
// States functions
// this function just toggle dropdown list
const toggle_dropdown = () => {
dropdown ? set_drop_down(false) : set_drop_down(true);
};
// this function shows all currencies inside dropdown list and when click on each item replace
// the currency info and hide dropdown list
const fetch_currency = (e) => {
set_drop_down(false);
currencies_info.map((currency) => {
if (e.target.id == currency.id) {
set_currency_name(currency.name);
set_currency_icon(currency.icon);
set_currency_price(currency.website_price);
}
});
};
// this function filter items base on user input value
const filter_currency = (e) => {
set_search_filter = currencies_info.filter((currency) => {
return currency.name.indexOf(e.target.value) !== -1;
});
api_data = set_search_filter;
console.log(api_data);
};
return (
<div className="buy-page-input" onClick={toggle_dropdown}>
{/* currency logo */}
<div className="currency-logo">
<img src={currency_icon} width="30px" />
</div>
{/* currency name in persian */}
<span className="currency-name">{currency_name}</span>
{/* currency dropdown icon */}
<div className="currency-dropdown">
<img className={dropdown ? "toggle-drop-down-icon" : ""}
src="https://img.icons8.com/ios-glyphs/30/000000/chevron-up.png"
/>
</div>
</div>
{/* Drop down list */}
{dropdown ? (
<div className="drop-down-list-container">
{/* Search box */}
<div className="search-box-container">
<input type="search" name="search-bar" id="search-bar"
placeholder="جستجو بر اساس اسم..."
onChange={(e) => {
filter_currency(e);
}}/>
</div>
{api_data.map((currency) => {
return (<div className="drop-down-list" onClick={(e) => {
fetch_currency(e);}} id={currency.id}>
<div class="right-side" id={currency.id}>
<img src={currency.icon} width="20px" id={currency.id} />
<span id={currency.id}>{currency.name}</span>
</div>
<div className="left-side" id={currency.id}>
<span id={currency.id}>قیمت خرید</span>
<span className="buy-price" id={currency.id}>
{currency.website_price}تومان</span>
</div>
</div>);})}
</div>) : ("")});}
Your search_filter looks redundant to me.
Try to change the filter_currency function like this:
const filter_currency = (e) => {
const search = e.target.value;
const filtered = currencies_info.filter((currency) => {
return currency.name.includes(search);
});
set_api_data(filtered);
};
It looks like you are never setting the api_data after you set the filter state.
Change the following
api_data = set_search_filter
console.log(api_data)
to
api_data = set_search_filter
set_api_data(api_data)
However, it then looks like set_search_filter is never used and only set so to improve this further you could remove that state and just have it set the api_data direct. Something like this:
const filter_currency = (e) => {
const search_filter = currencies_info.filter((currency) => {
return currency.name.indexOf(e.target.value) !== -1
})
set_api_data(search_filter)
}
Change your state value from string to array of the search_filter like this -
let [search_filter, set_search_filter] = useState([]);
and also it should be like this -
const filter_currency = (e) => {
const filterValues = currencies_info.filter((currency) => {
return currency.name.indexOf(e.target.value) !== -1;
});
set_search_filter(filtervalues);
set_api_data(filterValues);
console.log(filterValues);
};
and use useEffect with search_filter as dependency, so that every time search_filter value is being set, useEffect will trigger re render, for eg:-
useEffect(()=>{
//every time search_filter value will change it will update the dom.
},[search_filter])

Unable to successfully loop through a redux store after a dispatch function

I'm trying to add product items to my redux store called cart. After adding an item I then compare both stores product(redux store) and cart(redux store) to check if the product has the same itemCode(item code. if they do I would like to Hide the add button and show the remove button. Unfortunately I'm getting different results, please look at the picture below for reference:
interface IProps {
items: ItemInterface[];
documentItems: ItemInterface[];
onAddItem: any;
}
const ItemFlatList2: FC<Partial<IProps>> = ({
items,
documentItems,
onAddItem,
}) => {
return (
<div className={styles.container}>
<ul>
{items!.map((item) => {
return (
<div className={styles.itemContainer}>
<div key={item.itemCode}>
<li>{item.itemCode}</li>
<li>{item.itemDescription}</li>
{documentItems!.length === 0 ? (
<AddButton
title={"ADD"}
onClick={() =>
onAddItem(
item.itemCode,
item.itemDescription,
item.itemSellingPrice
)
}
/>
) : (
documentItems!.map((documentItem) => {
if (documentItem.itemCode === item.itemCode) {
return <RedButton title={"Remove"} />;
}
if (documentItem.itemCode !== item.itemCode) {
return (
<AddButton
title={"ADD"}
onClick={() =>
onAddItem(
item.itemCode,
item.itemDescription,
item.itemSellingPrice
)
}
/>
);
}
})
)}
</div>
<div>
<li>Hello world</li>
</div>
</div>
);
})}
</ul>
</div>
);
};
export default ItemFlatList2;
The Cart Store:
const initialState: Partial<DocumentDetailsInterface>[] = [
];
const cartStore = createSlice({
name: "quotation reducer",
initialState,
reducers: {
add: {
reducer: (
state,
{ payload }: PayloadAction<DocumentDetailsInterface>
) => {
state.push(payload);
},
prepare: (item) => ({
payload: item,
}),
},
edit: (state, { payload }) => {},
remove: (
state,
{ payload }: Partial<PayloadAction<DocumentDetailsInterface>>
) => {
const findItem = state.findIndex((item) => payload!.code === item.code);
if (findItem !== 1) {
state.splice(findItem, 1);
}
},
},
extraReducers: {},
});
and The Product Store:
const initialState: ItemInterface[] = [
{
_id: "sdfsd",
itemType: "Physical Item",
itemUnitOfMeasure: "Unit",
itemCode: "PPC10",
itemDescription: "PPC Cement",
itemCostPrice: 50,
itemSellingPrice: 80,
itemQuantity: 100,
vatStatus: "Standard rate 15%",
},
{
_id: "qew",
itemType: "Physical Item",
itemUnitOfMeasure: "Unit",
itemCode: "2",
itemDescription: "Sepako Cement",
itemCostPrice: 30,
itemSellingPrice: 60,
itemQuantity: 100,
vatStatus: "Standard rate 15%",
},
{
_id: "sdfsd",
itemType: "Physical Item",
itemUnitOfMeasure: "Unit",
itemCode: "1",
itemDescription: "PPC Cement",
itemCostPrice: 50,
itemSellingPrice: 80,
itemQuantity: 100,
vatStatus: "Standard rate 15%",
},
];
const itemSlice = createSlice({
name: "item reducer",
initialState,
reducers: {},
extraReducers: {},
});
It looks like you have wrong logic in you render method. You displayed "Add" button when there are no items in documentItems and the if any items inside you keep adding "Add" buttons if they are not equal to itemCode. So basically you have 2 loops. First is render items, and second one is to render buttons for each item. But you can use one loop to render items and have logic to check if that item is already in the documentItems array - if not then display "Add" button, else "Remove" button.
return (
<div className={styles.container}>
<ul>
{items!.map(item => {
return (
<div className={styles.itemContainer} key={item.itemCode}>
<div key={item.itemCode}>
<li>{item.itemCode}</li>
<li>{item.itemDescription}</li>
{documentItems!.findIndex(
documentItem => documentItem.itemCode === item.itemCode,
) === -1 ? (
<AddButton
title={'ADD'}
onClick={() =>
onAddItem(
item.itemCode,
item.itemDescription,
item.itemSellingPrice,
)
}
/>
) : (
<RedButton title={"Remove"} />
)}
</div>
<div>
<li>Hello world</li>
</div>
</div>
);
})}
</ul>
</div>
);
I think you need to provide a unique key to button. Write the statemen when you are changing the state
<AddButton
title={"ADD"}
key={item.itemCode}
onClick={() =>
onAddItem(
item.itemCode,
item.itemDescription,
item.itemSellingPrice
)
}
/>
You used map function to check if item exists in the documentItems. I think changing it to some function will work out.
documentItems!.some((documentItem) => {
return documentItem.itemCode === item.itemCode
}
) ? (<RedButton title={"Remove"} />): (
<AddButton
title={"ADD"}
onClick={() =>
onAddItem(
item.itemCode,
item.itemDescription,
item.itemSellingPrice
)
}
/>
);

State into index of array gives error REACT

I'm having issue where when i put my state into index of an array, it gives error.
Here is there line of bug : {WorkData[state].title}
What i need to do is to display the elements of WorkData which is a array with objects : title, content, img math etc...
const WorkData = [
{
id: 0,
title: 'title',
subtext: 'React/Express',
content: 'content',
imgPath: 'imgPath',
},
{
id: 1,
title: 'Little Hero Academy',
subtext: 'React/API REST',
content:
'content,
imgPath: 'imgPath',
},
{
id: 2,
title: 'title',
subtext: 'subtext',
content: 'content',
imgPath: 'imgPath',
},
First, i have a list of cards with a button that contains data:
<div className="work-container flex">
<div className="work-bloc zoom">
<div className="work-hover" />
<div className="work-text">
<div className="text-title">{WorkData[0].title}</div>
<span className="subtext">{WorkData[0].subtext}</span>
</div>
<div
onClick={togglePopup}
data-id={WorkData[0].id}
className="work-showmore button2"
>
Show More
</div>
</div>
</div>
I store the data in state with this function :
const [id, setId] = useState();
const togglePopup = (e) => {
setIsOpen(!isOpen);
setId(e.target.dataset.id);
};
I need that data to get to the popup,
<Popup
togglePopup={togglePopup}
closePopup={closePopup}
isOpen={isOpen}
id={id}
/>
I pass the state to my popup component and try to display the value of id which is displayed
Also,i need to make the popup display of the content of the array that belong to the id (index) i passed in state : workData 1 2 3 etc...
const Popup = ({ closePopup, isOpen, id }) => {
return (
<div className={`popup-container ${isOpen ? 'opened' : 'closed'}`}>
<div className={`popup ${isOpen ? 'opened2' : 'closed2'}`}>
<span className='popup-title'>
{WorkData[id].title}
{id}
</span>
<div className='image-container'>
<img
src='https://i.picsum.photos/id/1060/536/354.jpg?blur=2&hmac=0zJLs1ar00sBbW5Ahd_4zA6pgZqCVavwuHToO6VtcYY'
alt=''
/>
</div>
<p>
Team projet with React and API REST. Our goal was to make an app with
a choosen API and make something out of it. We did a superhero-themed
website with games for children.
<br />
Check on <AiFillGithub className='menuicon' />
</p>
<div onClick={closePopup} className='close-icon button2'>
Show less{' '}
</div>
</div>
</div>
);
};
but i get this error :
**TypeError: _WorkData__WEBPACK_IMPORTED_MODULE_1__.default[id] is undefined**
Thanks in advance for any suggestion
Ok i fixed, it i changed the way of doing it, i mapped my workcard components so i can easily retrieve the id, title, etc, and i didnt change the event onclick to catch the card.id in state, i passed the state to parent, then to the popup, and then into the popup component i just imported the WorkData.js and simply did : WorkData[state-with-id].title etc
See sample of code below
works.js
const togglePopup = (e) => {
setIsOpen(!isOpen);
setPopupId(e.target.dataset.id);
};
const closePopup = () => {
setIsOpen(false);
};
useEffect(() => {
setCards(workData);
}, []);
workcards.js
<div
onClick={togglePopup}
className='work-showmore button2'
data-id={workcard.id}
>
popup.js
import workData from './workData';
<span className='popup-title'>{workData[popupId].title}</span>

Handle Input with Same State Value

I'm building a shopping cart application and I ran into a problem where all my inputs have the same state value. Everything works fine but when I type in one input box, it's the same throughout all my other inputs.
I tried adding a name field to the input and setting my initial state to undefined and that works fine but the numbers don't go through.
How do we handle inputs to be different when they have the same state value? Or is this not possible / dumb to do?
class App extends Component {
state = {
items: {
1: {
id: 1, name: 'Yeezys', price: 300, remaining: 5
},
2: {
id: 2, name: 'Github Sweater', price: 50, remaining: 5
},
3: {
id: 3, name: 'Protein Powder', price: 30, remaining: 5
}
},
itemQuantity: 0
},
render() {
return (
<div>
<h1>Shopping Area</h1>
{Object.values(items).map(item => (
<div key={item.id}>
<h2>{item.name}</h2>
<h2>$ {item.price}</h2>
{item.remaining === 0 ? (
<p style={{ 'color': 'red' }}>Sold Out</p>
) : (
<div>
<p>Remaining: {item.remaining}</p>
<input
type="number"
value={ itemQuantity }
onChange={e => this.setState({ itemQuantity: e.target.value})}
placeholder="quantity"
min={1}
max={5}
/>
<button onClick={() => this.addItem(item)}>Add To Cart</button>
</div>
)}
</div>
))}
</div>
)
}
}
If you are using same state key for all input, All input take value from one place and update to one place. To avoid this you have to use separate state. I suppose you are trying to show input for a list of item.
To achive you can create a component for list item and keep state in list item component. As each component have their own state, state value will not conflict.
Here is an example
class CardItem extends Component {
state = {
number: 0
}
render() {
render (
<input type="text" value={this.state.number} onChange={e => this.setState({ number: e.target.value })} />
)
}
}
class Main extends Component {
render () {
const list = [0,1,2,3,4]
return (
list.map(item => <CardItem data={item} />)
)
}
}
This is a solution which the problem is loosely interpreted, but it does work without having to create another component. As you know, you needed to separate the state of each items in the cart. I did this by dynamically initializing and setting the quantity states of each item. You can see the state changes with this example:
class App extends React.Component {
constructor(props) {
super(props);
this.state = { quantities: {} }
}
componentDidMount() {
let itemIDs = ['1', '2', '3', 'XX']; //use your own list of items
itemIDs.forEach(id => {
this.setState({quantities: Object.assign(this.state.quantities, {[id]: 0})});
})
}
render() {
let list = Object.keys(this.state.quantities).map(id => {
return (
<div>
<label for={id}>Item {id}</label>
<input
id={id}
key={id}
type="number"
value={this.state.quantities[id]}
onChange={e => {
this.setState({quantities: Object.assign(this.state.quantities, {[id]: e.target.value})})
}}
/>
</div>
);
})
return (
<div>
{list}
<div>STATE: {JSON.stringify(this.state)}</div>
</div>
);
}
}
ReactDOM.render(<App/>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id='root'></div>
You can modify the state structure to your liking.
Here is how I usually handle this scenario. You say that you get an array of items? Each item object should contain a key to store the value (count in my example). You can use a generic onChange handler to update an individual item in the array. So now, your state is managing the list of items instead of each individual input value. This makes your component much more flexible and it will be able to handle any amount of items with no code changes:
const itemData = [
{ id: 0, count: 0, label: 'Number 1' },
{ id: 1, count: 0, label: 'Number 2' },
{ id: 2, count: 0, label: 'Number 3' },
{ id: 3, count: 0, label: 'Number 4' }
];
class App extends React.Component {
state = {
items: itemData
}
handleCountChange = (itemId, e) => {
// Get value from input
const count = e.target.value;
this.setState( prevState => ({
items: prevState.items.map( item => {
// Find matching item by id
if(item.id === itemId) {
// Update item count based on input value
item.count = count;
}
return item;
})
}))
};
renderItems = () => {
// Map through all items and render inputs
return this.state.items.map( item => (
<label key={item.label}>
{item.label}:
<input
type="number"
value={item.count}
onChange={this.handleCountChange.bind(this, item.id)}
/>
</label>
));
};
render() {
return (
<div>
{this.renderItems()}
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('root'));
label {
display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
You can't use the same state for the both inputs. Try to use a different state for each one like that:
class App extends Component {
state = {
number: ""
}
render() {
return (
<div>
<input
type="number"
value={this.state.number}
onChange={e => this.setState({ number: e.target.value })}
/>
<input
type="number"
value={this.state.number2}
onChange={e => this.setState({ number2: e.target.value })}
/>
</div>
)
}
}

Categories