react js how to add box counter - javascript

I want to add box in a counter in react js counter, but I do not know how to add in this application. I tried a lot after counter using react box material.
Here is my code of app.js like as this image shown:
`
import React, {useState} from "react";
import { Button} from 'react-bootstrap';
function App() {
const [count, setCount] = useState(0);//initial value is in parenthesis
return (
<div className="container my-10">
<div className="card text-center my-5">
<div className="card-body">
<h1>Counter App</h1>
<div className="my-5">
<h2 className="my-5">{count}</h2>
<div className="text-right">
<button
className="text-right rounded-circle btn btn-success mx-3"
onClick={() => setCount(count+1)}>+</button>
<button
className="rounded-circle btn btn-success mx-3"
onClick={() => setCount(count-1)}
disabled={count === 0}>-</button>
<Button type="reset"
onClick={() => setCount(0)}
disabled={count === 0}>Reset</Button>
</div>
</div>
</div>
</div>
</div>
);
}
export default App;

you mean something like this https://codesandbox.io/s/friendly-mclean-iuh9ig?file=/src/App.js:0-1415
import React, { useState } from "react";
import { Button } from "react-bootstrap";
function App() {
const [count, setCount] = useState(0); //initial value is in parenthesis
return (
<div className="container my-10">
<div className="card text-center my-5">
<div className="card-body">
<h1>Counter App</h1>
<div className="my-5">
<h2 className="my-5">{count}</h2>
<div className="text-right">
<button
className="text-right rounded-circle btn btn-success mx-3"
onClick={() => setCount(count + 1)}
>
+
</button>
<button
className="rounded-circle btn btn-success mx-3"
onClick={() => {
if (count > 0) {
setCount(count - 1);
}
}}
disabled={count === 0}
>
-
</button>
<Button
type="reset"
onClick={() => setCount(0)}
disabled={count === 0}
>
Reset
</Button>
</div>
</div>
{[...Array(count).keys()].map((item) => (
<div className="card">box {item + 1}</div>
))}
</div>
</div>
</div>
);
}
export default App;

Related

how to get values of state of that component that is inside map function react?

This is cart page of a ecommerce site.
Here I want to get the value of each indivisual counter value and multiply that with their respective price and show it into final checkout value. Here, i had hardcoded $160 but I want to make that dynamic. How can I do that or what would be best approach to achieve that.
My cart page
import React, { useState } from 'react'
import { RiDeleteBin6Line } from "react-icons/ri"
import Counter from '../../Components/Counter/Counter'
const Products = ({ cartdetails }) => {
const [value, setValue] = useState()
return (
<div className=' grid grid-cols-12 gap-4'>
{cartdetails.length === 0 ?
<div>No items in cart</div>
:
<div className=' col-span-8'>
{
cartdetails.map((data, index) => {
return (
<div className=' bg-gray-100 px-4 my-4 py-4'>
<div className=' flex justify-between'>
<img className=' w-24 h-24' src={data.productdetails.image} alt="" />
<div className=''>
<div className=' font-semibold text-lg'>
{data.productdetails.name}
</div>
<div className=' text-gray-400 text-sm'>
Color : {data.cartItems.color}
</div>
</div>
<div>
<div className='font-semibold text-lg'>${data.productdetails.price} USD</div>
<div className='text-gray-400 text-sm'>Price</div>
</div>
<div>
<div className=' font-semibold text-lg'>{data.productdetails.stock}</div>
<div className='text-gray-400 text-sm'>In Stock</div>
</div>
<button className=' h-fit text-gray-400'>
<RiDeleteBin6Line />
</button>
</div>
<Counter count={data.cartItems.quantity} {...data.productdetails} />
</div>
)
})
}
</div>
}
<div className=' col-span-4 my-4 '>
<div className=' px-4 py-8 flex flex-col gap-8 bg-gray-100'>
<div className=' flex justify-between'>
<div className=' font-bold'>Total</div>
<div className=' font-semibold'>$160USD</div>
</div>
<div className=' flex justify-end '>
<button className=' btn w-36 font-bold'>Checkout</button>
</div>
</div>
</div>
</div>
)
}
export default Products
Counter Component
import React, { useState } from 'react'
import { HiOutlineMinus } from "react-icons/hi"
import { GoPlus } from "react-icons/go"
import { incrementItem, decrementItem } from '../../redux/cart/changeCartNumber'
import { useSelector, useDispatch } from 'react-redux'
const Counter = ({ count, stock, _id }) => {
const [value, setValue] = useState(count)
return (
<div className='flex font-bold text-xl justify-end'>
<div className=' flex gap-4 bg-white p-2 w-40 justify-between '>
{/* <button className={`${state.value === 1 && "text-gray-400"}`} disabled={state.value === 1} onClick={() => dispatch(decrementItem({ _id, count }))}><HiOutlineMinus /></button> */}
<button onClick={() => setValue(value - 1)} disabled={value === 1} className={`${value === 1 && "text-gray-400"}`} ><HiOutlineMinus /></button>
<div>
{value}
</div>
<button onClick={() => setValue(value + 1)} disabled={value === stock} className={`${value === stock && "text-gray-400"}`}><GoPlus /></button>
</div>
</div>
)
}
export default Counter
You have to make another state in the parent component that will calculate the total on every child. your code will look like this:
import React, { useState } from 'react'
import { RiDeleteBin6Line } from "react-icons/ri"
import Counter from '../../Components/Counter/Counter'
const Products = ({ cartdetails }) => {
const [total, setTotal] = useState()
return (
<div className=' grid grid-cols-12 gap-4'>
{cartdetails.length === 0 ?
<div>No items in cart</div>
:
<div className=' col-span-8'>
{
cartdetails.map((data, index) => {
return (
<div className=' bg-gray-100 px-4 my-4 py-4'>
<div className=' flex justify-between'>
<img className=' w-24 h-24' src={data.productdetails.image} alt="" />
<div className=''>
<div className=' font-semibold text-lg'>
{data.productdetails.name}
</div>
<div className=' text-gray-400 text-sm'>
Color : {data.cartItems.color}
</div>
</div>
<div>
<div className='font-semibold text-lg'>${data.productdetails.price} USD</div>
<div className='text-gray-400 text-sm'>Price</div>
</div>
<div>
<div className=' font-semibold text-lg'>{data.productdetails.stock}</div>
<div className='text-gray-400 text-sm'>In Stock</div>
</div>
<button className=' h-fit text-gray-400'>
<RiDeleteBin6Line />
</button>
</div>
<Counter setTotal={setTotal} count={data.cartItems.quantity} {...data.productdetails} />
</div>
)
})
}
</div>
}
<div className=' col-span-4 my-4 '>
<div className=' px-4 py-8 flex flex-col gap-8 bg-gray-100'>
<div className=' flex justify-between'>
<div className=' font-bold'>Total</div>
<div className=' font-semibold'>{total}USD</div>
</div>
<div className=' flex justify-end '>
<button className=' btn w-36 font-bold'>Checkout</button>
</div>
</div>
</div>
</div>
)
}
export default Products
And now inside the Counter component you will update that state to calculate the total.
<button onClick={() => {setValue(value - 1); props.setTotal(prev=>prev+value-1)}} disabled={value === 1} className={`${value === 1 && "text-gray-400"}`} ><HiOutlineMinus /></button>
I don't know about getting the state back from a map function as it will be quite arduous for me, but why don't you try creating a totalPrice state in Products and then change the value of totalPrice by propDrilling setTotalPrice to Counter which will change its value on each and every change in their inventory (or cart).
const [totalPrice, setTotalPrice] = useState(0)
<Counter totalPrice={totalPrice} setTotalPrice={setTotalPrice} />
In counter you can
setTotalPrice(totalPrice + {whatever price it is for that specific increment/decrement}
Let me know if it works, I haven't tried it on a map function though. :)

Uncaught TypeError: Cannot read properties of undefined (reading 'params') react

I am creating an ecommerce with react. I'm trying to create a function who shows the product details. But I do not know how to approach this problem. After to be linked to the url of the details in the browser, the url is the right one, but the details are not renderer and get the following message:
ProductDetails.js:22 Uncaught TypeError: Cannot read properties of undefined (reading 'params')
Down here you can read the ProductDetails.js and App.js files.
This is my react-router-dom version v6.4.1
import { BrowserRouter, Route, Routes, Link } from 'react-router-dom';
import Header from './components/layout/Header';
import Footer from './components/layout/Footer';
import Home from './components/layout/Home'
import './App.css';
import ProductDetails from './components/product/ProductDetails';
function App() {
return(
<>
<Header/>
<Footer/>
<Routes>
<Route path='/' element={<Home/>} />
<Route path='/product/:id' element={<ProductDetails/>} />
<Route/>
</Routes>
</>
)
}
export default App;
import React, {useEffect, Fragment} from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { getProductDetails, clearErrors } from '../../actions/productActions';
import { useAlert } from 'react-alert';
import Loader from '../layout/Loader';
import MetaData from '../layout/MetaData';
const ProductDetails = ({match}) => {
const dispatch = useDispatch();
const alert = useAlert();
const {loading, error, product} = useSelector(state => state.productDetails)
useEffect(()=>{
dispatch(getProductDetails(match.params.id))
if(error){
alert.error(error);
dispatch(clearErrors());
}
},[dispatch, alert, error, match.params.id])
return (
<Fragment>
{loading ? <Loader/> : (
<Fragment>
<div className="row f-flex justify-content-around">
<div className="col-12 col-lg-5 img-fluid" id="product_image">
<img src="https://i5.walmartimages.com/asr/1223a935-2a61-480a-95a1-21904ff8986c_1.17fa3d7870e3d9b1248da7b1144787f5.jpeg?odnWidth=undefined&odnHeight=undefined&odnBg=ffffff" alt="sdf" height="500" width="500"/>
</div>
<div className="col-12 col-lg-5 mt-5">
<h3>"{product.name}</h3>
<p id="product_id">Product # sklfjdk35fsdf5090</p>
<hr/>
<div className="rating-outer">
<div className="rating-inner"></div>
</div>
<span id="no_of_reviews">(5 Reviews)</span>
<hr/>
<p id="product_price">$108.00</p>
<div className="stockCounter d-inline">
<span className="btn btn-danger minus">-</span>
<input type="number" className="form-control count d-inline" value="1" readOnly />
<span className="btn btn-primary plus">+</span>
</div>
<button type="button" id="cart_btn" className="btn btn-primary d-inline ml-4">Add to Cart</button>
<hr/>
<p>Status: <span id="stock_status">In Stock</span></p>
<hr/>
<h4 className="mt-2">Description:</h4>
<p>Binge on movies and TV episodes, news, sports, music and more! We insisted on 720p High Definition for this 32" LED TV, bringing out more lifelike color, texture and detail. We also partnered with Roku to bring you the best possible content with thousands of channels to choose from, conveniently presented through your own custom home screen.</p>
<hr/>
<p id="product_seller mb-3">Sold by: <strong>Amazon</strong></p>
<button id="review_btn" type="button" className="btn btn-primary mt-4" data-toggle="modal" data-target="#ratingModal">
Submit Your Review
</button>
<div className="row mt-2 mb-5">
<div className="rating w-50">
<div className="modal fade" id="ratingModal" tabIndex="-1" role="dialog" aria-labelledby="ratingModalLabel" aria-hidden="true">
<div className="modal-dialog" role="document">
<div className="modal-content">
<div className="modal-header">
<h5 className="modal-title" id="ratingModalLabel">Submit Review</h5>
<button type="button" className="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div className="modal-body">
<ul className="stars" >
<li className="star"><i className="fa fa-star"></i></li>
<li className="star"><i className="fa fa-star"></i></li>
<li className="star"><i className="fa fa-star"></i></li>
<li className="star"><i className="fa fa-star"></i></li>
<li className="star"><i className="fa fa-star"></i></li>
</ul>
<textarea name="review" id="review" className="form-control mt-3">
</textarea>
<button className="btn my-3 float-right review-btn px-4 text-white" data-dismiss="modal" aria-label="Close">Submit</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</Fragment>
)}
</Fragment>
)
}
export default ProductDetails
1-) Add the following line of code at the beginning of your class:
import { useParams } from 'react-router-dom';
2-) Then add this function above your class (copy it exactly):
export function withRouter(Children){
return(props)=>{
const match = {params: useParams()};
return <Children {...props} match = {match}/>
}
}
3-) Next, change your class definition to this:
class EditExercises extends Component{
4-) Add the following line of code at the end of your class:
export default withRouter(EditExercises);

Change boolean value onClick in React

I'm trying to change the value of a boolean from an object imported from a JSON file in React. I want the offers.availability value to change to false after clicking on the "add to cart" button.
Here's my code:
function App() {
class App {
constructor () {
this.state = {
offers: [],
}
this.handleToggle = this.handleToggle.bind(this);
}
componentDidMount() {
this.state.setState({ offers: Data });
}
handleToggle (offers) {
this.setState(prevState => ({
offers: prevState.offers.map(prevOffer => {
if (prevOffer.availability === offers.availability) {
return {
availability: prevOffer.availability,
isTrue: !prevOffer.isTrue
}
}
return prevOffer;
})}));
}
}
return (
<div className="container">
<div className="row">
{Data.offers.map(offers => {
return(
<div key={offers.make + offers.model + offers.engine + offers.photo} className="col-sm-4">
<div className="card" >
<img src={offers.photo} className="card-img-top" alt={offers.make + ' ' + offers.model } width="100%"/>
<div className="card-body pt-0 px-0">
<div className="d-flex flex-row justify-content-between mb-0 px-3 p-3 mid">
<div className="d-flex flex-column">
<h4>{offers.make} {offers.model}</h4>
</div>
<div className="d-flex flex-column">
<button type="button" className="btn btndelete"><FaTrash /></button>
</div>
</div>
<div className="d-flex flex-row justify-content-between px-3">
<div className="d-flex flex-column"><span className="text-muted">Engine: {offers.engine}</span></div>
<div className="d-flex flex-column">
{offers.availability.toString()}
</div>
</div>
<div className="mx-3 mt-3 mb-2 d-grid gap-2">
{offers.availability
? <button type="button" className="btn btn-primary addtocartbtn" onClick={() => Data.offers.handleToggle(offers)}>
<small>Add to cart</small>
</button>
: <button type="button" className="btn btn-disabled" onClick={console.log('???')}><small>Currently unavailabe</small></button>
}
</div>
</div>
</div>
</div>
)
}) }
</div>
</div>
)}
export default App;
I tried to toggle the boolean value but I currently get a ".offers.handleToggle is not a function" error after clicking.
I'm new to this so please don't judge if I did something really stupid here :) What could be the possible solution to this?
You should not use Data.offers.handleToggle. From what I see, Data.offers is an array of objects which they don't have a function handleToggle defined.
However, you are defining a function handleToggle on the App component that looks good. It should work if you change onClick={() => Data.offers.handleToggle(offers)} with either onClick={() => handleToggle(offers)} or onClick={() => this.handleToggle(offers)}
UPDATE
After running your code I saw the component is defined as a mix of a functional component and a class component. First, decide what you are going to use and then fix the errors 1 by 1. The constructor for example is missing the props, there are onclicks that are not well defined and a few more things.
Here is your code if used as a class component.
import { Component } from "react";
export class App extends Component<{}, { offers: any[] }> {
constructor(props: {}) {
super(props);
this.state = {
offers: [],
};
this.handleToggle = this.handleToggle.bind(this);
}
componentDidMount() {
this.setState({ offers: Data });
}
handleToggle(offers: any) {
this.setState((prevState) => ({
offers: prevState.offers.map((prevOffer) => {
if (prevOffer.availability === offers.availability) {
return {
availability: prevOffer.availability,
isTrue: !prevOffer.isTrue,
};
}
return prevOffer;
}),
}));
}
render() {
return (
<div className="container">
<div className="row">
{this.state.offers.map((offers) => {
return (
<div
key={offers.make + offers.model + offers.engine + offers.photo}
className="col-sm-4"
>
<div className="card">
<img
src={offers.photo}
className="card-img-top"
alt={offers.make + " " + offers.model}
width="100%"
/>
<div className="card-body pt-0 px-0">
<div className="d-flex flex-row justify-content-between mb-0 px-3 p-3 mid">
<div className="d-flex flex-column">
<h4>
{offers.make} {offers.model}
</h4>
</div>
<div className="d-flex flex-column">
<button type="button" className="btn btndelete">
<FaTrash />
</button>
</div>
</div>
<div className="d-flex flex-row justify-content-between px-3">
<div className="d-flex flex-column">
<span className="text-muted">
Engine: {offers.engine}
</span>
</div>
<div className="d-flex flex-column">
{offers.availability.toString()}
</div>
</div>
<div className="mx-3 mt-3 mb-2 d-grid gap-2">
{offers.availability ? (
<button
type="button"
className="btn btn-primary addtocartbtn"
onClick={() => this.handleToggle(offers)}
>
<small>Add to cart</small>
</button>
) : (
<button
type="button"
className="btn btn-disabled"
onClick={() => console.log("???")}
>
<small>Currently unavailabe</small>
</button>
)}
</div>
</div>
</div>
</div>
);
})}
</div>
</div>
);
}
}
You just need to define the offers type and a FaTrash component

am Unable to calculate the prices in the cart List-ReactJS

I am doing a cart page here, the cart page will display the items to the which user has been added and it will display its price also. On the same page, i want to display the Grand total amount of all the items present on the cart Page in Payment Summary(order summary)
Please help me am new to React.
Here is my ReactJS code of Cart page
import React, { useEffect, useState } from 'react';
import { useHistory } from 'react-router';
import '../cart.css';
function Cart() {
const tvalue = 0;
const [cart, setCart] = useState([]);
const [paymentsummery, setpaymentsummery] = useState(0);
const [total, setTotal] = useState('');
const [loading, setLoading] = useState(true);
const [cartSate, setcartState] = useState(true);
const [id, setID] = useState('');
const history = useHistory();
useEffect(() => {
const fetchUser = async () => {
try {
const responce = await fetch('/getcartItems', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
});
const resp = await responce.json();
console.log(resp);
setCart(resp);
setLoading(false);
setID(resp[0]._id);
setcartState(true);
if (!responce) {
alert('user not authorized');
history.push('/');
} else if (responce.status == 400) {
history.push('/');
} else if (responce.status == 401) {
alert('cart is empty');
}
} catch {
// alert('cart is empty')
setcartState(false);
}
};
fetchUser();
}, []);
if (cartSate == true) {
return (
<div className="cart_cont row container-fluid">
{loading ? (
<div className="loading_div">
<h1 className="loading">Loading...</h1>
</div>
) : (
cart.map((itms, index) => (
<div key={index} className="innerCart my-0 col-8">
<div className="cartDetails">
<div className="slno d-flex flex-column">
<label htmlFor="" className="text-danger m-auto">
Sl.No
</label>
<p className="m-auto">{index + 1}</p>
</div>
<div className="cartImage ">
<img
src={itms.productimage}
alt="cart_image"
height="100px"
/>
</div>
<div className="title d-flex flex-column">
<label htmlFor="" className="text-danger m-auto">
Item Name
</label>
<p className="m-auto">{itms.productname}</p>
</div>
<div className="qty d-flex flex-column">
<label htmlFor="" className="text-danger m-auto">
Quantity
</label>
<p className="m-auto">{itms.qty}</p>
</div>
<div className="tprice d-flex flex-column">
<label htmlFor="" className="text-danger m-auto">
Price
</label>
<p className="m-auto">{itms.totalprice}</p>
</div>
<div className="d-flex ">
<i className="fas fa-trash m-auto" />
</div>
</div>
<hr />
</div>
))
)}
{loading ? (
<div />
) : (
<div className="priceDetails col-4 ">
<div className="innerPriceDetails rounded">
<h1 className="paymentSummery h3 p-2">Payment Summery </h1>
<div className=" d-flex justify-content-between mx-2 my-2">
<span>Transaction code</span>
<span>Vd7jl0rq9ppe</span>
</div>
<div className="coupen d-flex m-3 justify-content-between">
<input
type="text"
className="form-control mr-2"
placeholder="COUPON CODE"
/>
<button className="btn btn-info px-5">Apply</button>
</div>
<hr />
<div className="order_summery m-3">
<div className="d-flex justify-content-between">
<h5>Order Summery</h5>
<h5>Rs. </h5>
</div>
<div className="d-flex justify-content-between">
<h5>Shipping charges</h5>
<h5>Rs. 10</h5>
</div>
<div className="d-flex justify-content-between">
<h5>Additional services</h5>
<h5>Rs. 00</h5>
</div>
<div className="d-flex justify-content-between">
<h5 className="font-weight-bold">Total amount</h5>
<h5 className="font-weight-bold">Rs. 5400</h5>
</div>
<hr />
<p className="d-flex bg-danger expires text-white p-2 rounded justify-content-between">
Sale Expires in: 21Hours, 31 Minutes
</p>
</div>
</div>
<button className="btn btn-warning w-100 my-3 font-weight-bold p-2">
CHECKOUT
</button>
</div>
)}
</div>
);
}
return (
<div>
<h1 className="display-3 mt-5">CART IS EMPTY!</h1>
</div>
);
}
export default Cart;
above, I have shared my whole code of the cart page, Usually, the cart data will be displayed from the database.
Please help me.
For that, you would use Array.reduce to calculate for grandTotal:
Before your return function:
const grandTotal = cart.reduce((a, c) => a + c.totalprice, 0);
Then you can place grandTotal where ever you want to display it.

Filter not working proper in react its working only for first time also how to filter true and false

Here is my code
https://stackblitz.com/edit/react-nsxxqp?file=src%2FApp.js
and my local code is here how to filter i don't know i am new for react and JavaScript please help me i don't know how to finish my task.
import React, { useEffect, useState } from "react";
const Product = (props) => {
const [allButtons, setAllButtons] = useState([]);
const [product, setProduct] = useState([]);
useEffect(() => {
fetch("https://api.spacexdata.com/v3/launches?limit=100")
.then(response => response.json())
.then(productsList => {
setProduct(productsList);
setAllButtons(productsList);
});
}, []);
const onBtnClick = (e) =>{
setProduct(product.filter(i=>i.launch_year == e));
};
return(
<div className="container-fluid">
<div className="row">
<div className="col-xl-12">
<h2>SpacesX Launch Programme</h2>
</div>
</div>
<div className="row">
<div className="col-xl-2 col-lg-2 col-md-2 col-sm-2 col-xs-12">
<div className="inner">
<p className="bold">Filter</p>
<div className="col12 launchYear">
<p className="marg0">Launch Year</p>
{allButtons.map(productYr => (
<button
className="btn btn-primary btnSpacex"
key={productYr.launch_year}
onClick={(e) => onBtnClick(productYr.launch_year)}
>
{productYr.launch_year}
</button>
))}
</div>
<div className="clearfix" />
<div className="col12 launchYear">
<p className="marg0">Successful Launch</p>
<button className="btn btn-default btnSpacex">True</button>
<button className="btn btn-default btnSpacex">False</button>
</div>
<div className="clearfix" />
<div className="col12 launchYear">
<p className="marg0">Successful Landing</p>
<button className="btn btn-default btnSpacex">True</button>
<button className="btn btn-default btnSpacex">False</button>
</div>
</div>
</div>
<div className="col-xl-10 col-lg-10 col-md-10 col-sm-10 col-xs-12 items1">
<div className="row">
{product.map(product => (
<div
key={product.flight_number}
className="col-xl-3 col-lg-3 col-md-3 col-sm-3 col-xs-12 marginBottom15"
>
<div className="inner">
<img
src={product.links.mission_patch}
className="full-width imgBg"
alt={product.mission_name}
/>
<div className="clearfix" />
<p className="productName bold margBot5">
{product.mission_name} #{product.flight_number}
</p>
<div className="clearfix" />
<p className="bold margBot5">
Mission Ids:
<ul className="marg0 blueClr">
<li>{product.mission_id}</li>
</ul>
</p>
<div className="clearfix" />
<p className="bold margBot5">
Launch Year:{" "}
<span className="normal blueClr">
{product.launch_year}
</span>
</p>
<div className="clearfix" />
<p className="bold margBot5">
Successful Launch:{" "}
<span className="normal blueClr">
{product.launch_success}
</span>
</p>
<div className="clearfix" />
<p className="bold margBot5">
Successful Landing:{" "}
<span className="normal blueClr">
{product.rocket.land_success}
</span>
</p>
</div>
</div>
))}
</div>
</div>
</div>
</div>
)
}
export default Product
Main issue here is your onButtonClick function. Change it to the following code (instead of product.filter, use allButtons.filter):
const onBtnClick = e => {
setProduct(allButtons.filter(i => i.launch_year == e));
};
The problem was that you had all of your products, then when you selected the first button, you set the product to just that button. On the next click, you're trying to filter on just the single product that you selected in the first click. To get around this, you want the filter to always be on the allButtons list (I'm assuming this was just a small oversight on your part, it looks like you knew exactly what you were trying to do but just accidentally put the wrong list in the function).
Another small change that I would make to your code is below: (introduce index parameter and use it as the key):
{allButtons.map((productYr, index) => (
<button
className="btn btn-primary btnSpacex"
key={index}
onClick={e => onBtnClick(productYr.launch_year)}
>
{productYr.launch_year}
</button>
))
}
This will eliminate all those console warnings that you're getting for having duplicate keys.
Check below code
import React, { useEffect, useState } from "react";
const Product = (props) => {
const [allButtons, setAllButtons] = useState([]);
const [launchSuccess, launchAllSuccess] = useState([]);
const [landSuccess, landAllSuccess] = useState([]);
const [product, setProduct] = useState([]);
useEffect(() => {
fetch("https://api.spacexdata.com/v3/launches?limit=100")
.then(response => response.json())
.then(productsList => {
setProduct(productsList);
setAllButtons(productsList);
launchAllSuccess(productsList);
landAllSuccess(productsList);
});
}, []);
const onBtnClick = e => {
setProduct(allButtons.filter(i => i.launch_year === e));
};
const onBtnLaunchAllSuccess = e =>{
setProduct(launchSuccess.filter(i => i.launch_success === e));
}
const onBtnLandSuccessful = e =>{
setProduct(landSuccess.filter(i => i.rocket.first_stage.cores[0].land_success === e));
}
return(
<div className="container-fluid">
<div className="row">
<div className="col-xl-12">
<h2>SpacesX Launch Programme</h2>
</div>
</div>
<div className="row">
<div className="col-xl-2 col-lg-2 col-md-2 col-sm-2 col-xs-12">
<div className="inner">
<p className="bold">Filter</p>
<div className="col12 launchYear">
<p className="marg0">Launch Year</p>
{allButtons.map((productYr, index) => (
<button
className="btn btn-primary btnSpacex"
key={index}
onClick={e => onBtnClick(productYr.launch_year)}
>
{productYr.launch_year}
</button>
))
}
</div>
<div className="clearfix" />
<div className="col12 launchYear">
<p className="marg0">Successful Launch</p>
<button
onClick={e => onBtnLaunchAllSuccess(true)}
className="btn btn-default btnSpacex">True</button>
<button
onClick={e => onBtnLaunchAllSuccess(false)}
className="btn btn-default btnSpacex">False</button>
</div>
<div className="clearfix" />
<div className="col12 launchYear">
<p className="marg0">Successful Landing</p>
<button
onClick={e => onBtnLandSuccessful(true)}
className="btn btn-default btnSpacex">True</button>
<button
onClick={e => onBtnLandSuccessful(false)}
className="btn btn-default btnSpacex">False</button>
</div>
</div>
</div>
<div className="col-xl-10 col-lg-10 col-md-10 col-sm-10 col-xs-12 items1">
<div className="row">
{product.map(product => (
<div
key={product.flight_number}
className="col-xl-3 col-lg-3 col-md-3 col-sm-3 col-xs-12 marginBottom15"
>
<div className="inner">
<img
src={product.links.mission_patch}
className="full-width imgBg"
alt={product.mission_name}
/>
<div className="clearfix" />
<p className="productName bold margBot5">
{product.mission_name} #{product.flight_number}
</p>
<div className="clearfix" />
<p className="bold margBot5">
Mission Ids:
<ul className="marg0 blueClr">
<li>{product.mission_id}</li>
</ul>
</p>
<div className="clearfix" />
<p className="bold margBot5">
Launch Year:
<span className="normal blueClr">
{product.launch_year}
</span>
</p>
<div className="clearfix" />
<p className="bold margBot5">
Successful Launch:
<span className="normal blueClr">
{product.launch_success}
</span>
</p>
<div className="clearfix" />
<p className="bold margBot5">
Successful Landing:
<span className="normal blueClr">
{product.rocket.first_stage.cores[0].land_success}
</span>
</p>
</div>
</div>
))}
</div>
</div>
</div>
</div>
)
}
export default Product

Categories

Resources