(ReactJS) Separate trigger for each Collapsible element (react-collapsible) - reactjs

How can I make a separate trigger for each Collapsible element with a single useState (preferably)?
CodeSandBox - https://codesandbox.io/s/separate-triggers-question-forked-vgs5b
App.js
import React from "react";
import Collapsible from "react-collapsible";
function App() {
const database = [
{ id: 1, name: "Name1", description: "Desc1" },
{ id: 2, name: "Name2", description: "Desc2" },
{ id: 3, name: "Name3", description: "Desc3" },
{ id: 4, name: "Name4", description: "Desc4" },
{ id: 5, name: "Name5", description: "Desc5" }
];
const [items, setItems] = React.useState(database);
const [open, setOpen] = React.useState(false);
return (
<div className="tracker_master">
{items.map((item, index) => (
<div onClick={() => setOpen(!open)} key={item.id}>
{item.name.toUpperCase()}
<Collapsible open={open}>
<div>{item.description.toUpperCase()}</div>
</Collapsible>
</div>
))}
</div>
);
}
export default App;

To have seperate triggers for each item I recommend to abstract each element into its own component that has its own open state.
So you could do something like this:
const Item = ({ item }) => {
const [open, setOpen] = React.useState(false);
return (
<div onClick={() => setOpen(!open)} key={item.id}>
{item.name.toUpperCase()}
<Collapsible open={open}>
<div>{item.description.toUpperCase()}</div>
</Collapsible>
</div>
);
};
function App() {
const database = [
{ id: 1, name: "Name1", description: "Desc1" },
{ id: 2, name: "Name2", description: "Desc2" },
{ id: 3, name: "Name3", description: "Desc3" },
{ id: 4, name: "Name4", description: "Desc4" },
{ id: 5, name: "Name5", description: "Desc5" }
];
return (
<div className="tracker_master">
{database.map((item) => (
<Item item={item} key={item.id} />
))}
</div>
);
}
sandbox example

If you want to use single useState then your single state object should manage open flag of all the items as shown below (I have updated your code and tested its working fine).
openFlags is single state which maintains the open flag of each item by id and use it for triggering collabse and expand the items independently.
import React from "react";
import Collapsible from "react-collapsible";
function App() {
const database = [
{ id: 1, name: "Name1", description: "Desc1" },
{ id: 2, name: "Name2", description: "Desc2" },
{ id: 3, name: "Name3", description: "Desc3" },
{ id: 4, name: "Name4", description: "Desc4" },
{ id: 5, name: "Name5", description: "Desc5" }
];
const [items, setItems] = React.useState(database);
let initialOpenFlags = {}
items.forEach((i) => {
initialOpenFlags = {
...initialOpenFlags,
[i.id]: false
};
});
const [openFlags, setOpenFlags] = React.useState(initialOpenFlags);
return (
<div className="tracker_master">
{items.map((item, index) => (
<div
onClick={() =>
setOpenFlags({ ...openFlags, [item.id]: !openFlags[item.id] })
}
key={item.id}
>
{item.name.toUpperCase()}
<Collapsible open={openFlags[item.id]}>
<div>{item.description.toUpperCase()}</div>
</Collapsible>
</div>
))}
</div>
);
}
export default App;

Related

How to subtract values from one array of objects from another array of object using the same ID in REACT JS

I have two arrays of objects.
I'm trying to create a function that can subtract values from one array of objects from another array of object using the same id on name in REACT
export default function App() {
const stockArray = [
{ id: 1, name: "Iphone", amount: 23 },
{ id: 2, name: "Samsung", amount: 28 },
{ id: 3, name: "Huawei", amount: 14 },
{ id: 4, name: "Motorola", amount:20 }
];
const basketArray = [
{ id: 1, name: "Iphone", amount: 3 },
{ id: 3, name: "Huawei", amount: 4 }
];
const [stock, setStock] = React.useState(stockArray);
const [basket, setBasket] = React.useState(basketArray);
const handleUpdateStock = () => {
// How to subtract amount values in basketArray from amount values in stockArray
in objects with the same id or name.
// the result should be :
// const stockArray = [
// { id: 1, name: "Iphone", amount: 20 },
// { id: 2, name: "Samsung", amount: 28 },
// { id: 3, name: "Huawei", amount: 10 },
// { id: 4, name: "Motorola", amount:20 }
// ];
}
return (
<div>
<h3>Stock:</h3>
{stock.map(product=> (
<h5>{product.name} - {product.amount} </h5>
))}
<br/>
<h3>Basket:</h3>
{basket.map(product=> (
<h5>{product.name} - {product.amount} </h5>
))}
<button onClick={handleUpdateStock}>Save and update stock </button>
</div>
);
}`
You can loop your stock array, and compare each product with in it with each product from the basket.
If they have the same id you should subtract the amount from the product.amount from the the product inside the basket.
In the end we should setStock with the new array.
function App() {
const stockArray = [
{ id: 1, name: "Iphone", amount: 23 },
{ id: 2, name: "Samsung", amount: 28 },
{ id: 3, name: "Huawei", amount: 14 },
{ id: 4, name: "Motorola", amount:20 }
];
const basketArray = [
{ id: 1, name: "Iphone", amount: 3 },
{ id: 3, name: "Huawei", amount: 4 }
];
const [stock, setStock] = React.useState(stockArray);
const [basket, setBasket] = React.useState(basketArray);
const handleUpdateStock = () => {
const newStock = stock.map(product => {
const productInBasket = basket.find(el => el.id === product.id);
if (!productInBasket) return product;
return {
...product,
amount: product.amount - productInBasket.amount,
}
})
setStock(newStock);
}
return (
<div>
<h3>Stock:</h3>
{stock.map(product=> (
<h5 key={product.id}>{product.name} - {product.amount} </h5>
))}
<br/>
<h3>Basket:</h3>
{basket.map(product=> (
<h5 key={product.id}>{product.name} - {product.amount} </h5>
))}
<button onClick={handleUpdateStock}>Save and update stock </button>
</div>
);
}
ReactDOM.createRoot(
document.getElementById("root")
).render(
<App />
);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.development.js"></script>
function substract (stockArray,basketArray){
return stockArray.map(stock=>{
const basket = basketArray.find(basket=>stock.id===basket.id);
if(basket){
return {
...stock,
amount:stock.amount-basket.amount,
}
} else {
return stock;
}
})
}
this function iterates all indexes in stockArray, will find same object with the same id in basketArray and if basket is an object, it changes value of amount in stock

Parsing error: ',' expected. with array map function

this is very simple react code, but I cannot figure out why it's so mad at me for trying to do a map. I double check the closing brackets and that the key matches and I've tried adding semi colon all over and nothing happened, the error is "Parsing error: ',' expected." on my recipes object but everything checks out. Thanks for any help!
import React from "react";
const RecipeCard = () => {
const recipes = [
{
id: "recipe-id-1",
name: "Tomato Soup",
description: "Love red soup 😎",
ingredient: [
{ name: "tomato", measurement: 3, unit: "cup" },
{ name: "water", measurement: 3, unit: "cup" },
]
},
{
id: "recipe-id-2",
name: "Potato Soup",
description: "Love potato soup 😎",
ingredient: [
{ name: "potato", measurement: 3, unit: "cup" },
{ name: "water", measurement: 3, unit: "cup" },
]
}
];
return (
{recipes.map((recipe) => (
<div className="recipeCard">
<h2>{recipe.name}</h2>
<p>{recipe.description}</p>
<ul>
{recipe.ingredient.map((ingredient) => (
<li>
{ingredient.name} - {ingredient.measurement}
{ingredient.unit}
</li>
))}
</ul>
</div>
))}
)
}
export default RecipeCard;
you need to group the content. use </> fragment
return (
<>
{recipes.map((recipe) => (
<div className="recipeCard">
<h2>{recipe.name}</h2>
<p>{recipe.description}</p>
<ul>
{recipe.ingredient.map((ingredient) => (
<li>
{ingredient.name} - {ingredient.measurement}
{ingredient.unit}
</li>
))}
</ul>
</div>
))}
</>
)
Do not use default export and wrap the output in a div:
import React from "react";
export const RecipeCard = () => {
const recipes = [
{
id: "recipe-id-1",
name: "Tomato Soup",
description: "Love red soup 😎",
ingredient: [
{ name: "tomato", measurement: 3, unit: "cup" },
{ name: "water", measurement: 3, unit: "cup" },
]
},
{
id: "recipe-id-2",
name: "Potato Soup",
description: "Love potato soup 😎",
ingredient: [
{ name: "potato", measurement: 3, unit: "cup" },
{ name: "water", measurement: 3, unit: "cup" },
]
}
];
return (
<div>
{recipes.map((recipe) => (
<div className="recipeCard">
<h2>{recipe.name}</h2>
<p>{recipe.description}</p>
<ul>
{recipe.ingredient.map((ingredient) => (
<li>
{ingredient.name} - {ingredient.measurement}
{ingredient.unit}
</li>
))}
</ul>
</div>
))}
</div>
)
}

How to show length of filtered items using react redux. Im getting data using list. Using list how can i get the length of filtered items length

This is shop page.jsx file here i want to show the list of filtered items at the top of the page. Here im using data list for getting all the details. Here i want to show length of filtered products at showing 9 0f 9 products.
import React, { useEffect, useState } from 'react';
import EmptyView from '../components/common/EmptyView';
import FilterPanel from '../components/Home/FilterPanel';
import List from './Home/List';
// import SearchBar from '../../components/Home/SearchBar';
import { dataList } from '../constants';
// import './styles.css';
import '../App.css';
import ButtonAppBar from "./Header";
const Shop = () => {
// const [selectedCategory, setSelectedCategory] = useState(null);
// const [selectedRating, setSelectedRating] = useState(null);
const [selectedPrice, setSelectedPrice] = useState([0, 150]);
const [cuisines, setCuisines] = useState([
{ id: 1, checked: false, label: 'Furniture' },
{ id: 2, checked: false, label: 'Decoration' },
{ id: 3, checked: false, label: 'Bedding' },
{ id: 4, checked: false, label: 'Lighting' },
{ id: 5, checked: false, label: 'Bath&Shower' },
{ id: 6, checked: false, label: 'Curtains' },
{ id: 7, checked: false, label: 'Toys' },
]);
const [brand, setBrand] = useState([
{ id: 1, checked: false, label: 'Poliform' },
{ id: 2, checked: false, label: 'Rochie Bobois' },
{ id: 3, checked: false, label: 'Edra' },
{ id: 4, checked: false, label: 'Kartell' },
]);
const [availability, setAvailability] = useState([
{ id: 1, checked: false, label: 'Onstock' },
{ id: 2, checked: false, label: 'Outofstock' },
]);
const [list, setList] = useState(dataList);
const [resultsFound, setResultsFound] = useState(true);
// const [searchInput, setSearchInput] = useState('');
// const handleSelectCategory = (event, value) =>
// !value ? null : setSelectedCategory(value);
// const handleSelectRating = (event, value) =>
// !value ? null : setSelectedRating(value);
const handleChangeChecked = (id) => {
const cusinesStateList = cuisines;
const changeCheckedCuisines = cusinesStateList.map((item) =>
item.id === id ? { ...item, checked: !item.checked } : item
);
setCuisines(changeCheckedCuisines);
};
const handleChangeCheckeds = (id) => {
const brandStateList = brand;
const changeCheckedsBrand = brandStateList.map((item) =>
item.id === id ? { ...item, checked: !item.checked } : item
);
setBrand(changeCheckedsBrand);
};
const handleChangeCheckedss = (id) => {
const availabilityStateList = availability;
const changeCheckedssAvailability = availabilityStateList.map((item) =>
item.id === id ? { ...item, checked: !item.checked } : item
);
setAvailability(changeCheckedssAvailability);
};
const handleChangePrice = (event, value) => {
setSelectedPrice(value);
};
const applyFilters = () => {
let updatedList = dataList;
// // Rating Filter
// if (selectedRating) {
// updatedList = updatedList.filter(
// (item) => parseInt(item.rating) === parseInt(selectedRating)
// );
// }
// // Category Filter
// if (selectedCategory) {
// updatedList = updatedList.filter(
// (item) => item.category === selectedCategory
// );
// }
// Cuisine Filter
const cuisinesChecked = cuisines
.filter((item) => item.checked)
.map((item) => item.label.toLowerCase());
if (cuisinesChecked.length) {
updatedList = updatedList.filter((item) =>
cuisinesChecked.includes(item.cuisine)
);
}
// brand filter
const brandChecked = brand
.filter((item) => item.checked)
.map((item) => item.label.toLowerCase());
if (brandChecked.length) {
updatedList = updatedList.filter((item) =>
brandChecked.includes(item.brand)
);
}
// availabilty filter
const availabilityChecked = availability
.filter((item) => item.checked)
.map((item) => item.label.toLowerCase());
if (availabilityChecked.length) {
updatedList = updatedList.filter((item) =>
availabilityChecked.includes(item.availability)
);
}
// // Search Filter
// if (searchInput) {
// updatedList = updatedList.filter(
// (item) =>
// item.title.toLowerCase().search(searchInput.toLowerCase().trim()) !==
// -1
// );
// }
// // Price Filter
const minPrice = selectedPrice[0];
const maxPrice = selectedPrice[1];
updatedList = updatedList.filter(
(item) => item.price >= minPrice && item.price <= maxPrice
);
setList(updatedList);
!updatedList.length ? setResultsFound(false) : setResultsFound(true);
};
useEffect(() => {
applyFilters();
}, [cuisines, brand, availability, selectedPrice]);
return (
<div>
<ButtonAppBar />
<div className='home'>
{/* Search Bar */}
{/* <SearchBar
value={searchInput}
changeInput={(e) => setSearchInput(e.target.value)}
/> */}
<br /><br /><br /> <div className='home_panelList-wrap'>
{/* Filter Panel */}
<div className='home_panel-wrap'>
<FilterPanel
// selectedCategory={selectedCategory}
// selectCategory={handleSelectCategory}
// selectedRating={selectedRating}
selectedPrice={selectedPrice}
// selectRating={handleSelectRating}
cuisines={cuisines}
changeChecked={handleChangeChecked}
brand={brand}
changeCheckeds={handleChangeCheckeds}
availability={availability}
changeCheckedss={handleChangeCheckedss}
changePrice={handleChangePrice}
/>
</div>
{/* List & Empty View */}
<div className='home_list-wrap'>
<h6>Showing
<span style={{ color: "#bd744c" }}><b>{dataList.length}</b></span> of
<span style={{ color: "#bd744c" }}><b>9</b></span>
Products</h6>
{resultsFound ? <List list={list} /> : <EmptyView />}
</div>
</div>
</div>
</div>
);
};
export default Shop;
This is constant.js file from here we are getting all our details in shop.jsx file.
export const dataList = [
{
id: 1,
title: 'AwesomeLamp',
cuisine: 'lighting',
price: 40,
image: '/images/AwesomeLamp.png',
brand: 'poliform',
availability: 'onstock',
name: 'AwesomeLamp',
tagName: 'AwesomeLamp'
},
{
id: 2,
title: 'CozySofa',
cuisine: 'furniture',
price: 150,
image: '/images/CozySofa.png',
brand: 'edra',
availability: 'outofstock',
name: 'CozySofa',
tagName: 'CozySofa'
},
{
id: 3,
title: 'AwesomeCandle',
cuisine: 'lighting',
price: 15,
image: '/images/AwesomeCandle.png',
brand: 'kartell',
availability: 'onstock',
name: 'AwesomeCandle',
tagName: 'AwesomeCandle',
},
{
id: 4,
title: 'FancyChair',
cuisine: 'furniture',
price: 70,
image: '/images/FancyChair.png',
brand: 'poliform',
availability: 'outofstock',
name: 'FancyChair',
tagName: 'FancyChair'
},
{
id: 5,
title: 'ChineseTeapot',
cuisine: 'decoration',
price: 50,
image: '/images/ChineseTeapot.png',
brand: 'rochie bobois',
availability: 'onstock',
name: 'ChineseTeapot',
tagName: 'ChineseTeapot'
},
{
id: 6,
title: 'SoftPillow',
cuisine: 'bedding',
price: 30,
image: '/images/SoftPillow.png',
brand: 'edra',
availability: 'onstock',
name: 'SoftPillow',
tagName: 'SoftPillow'
},
{
id: 7,
title: 'WoodenCasket',
cuisine: 'decoration',
price: 20,
image: '/images/WoodenCasket.png',
brand: 'kartell',
availability: 'onstock',
name: 'WoodenCasket',
tagName: 'WoodenCasket'
},
{
id: 8,
title: 'AwesomeArmChair',
cuisine: 'furniture',
price: 90,
image: '/images/AwesomeArmChair.png',
brand: 'poliform',
availability: 'onstock',
name: 'AwesomeArmchair',
tagName: 'AwesomeArmchair'
},
{
id: 9,
title: 'CoolFlower',
cuisine: 'decoration',
price: 20,
image: '/images/CoolFlower.png',
brand: 'none',
availability: 'onstock',
name: 'CoolFlower',
tagName: 'CoolFlower'
},
];

Filtering an array of products

I'm a newbie and I try to set up a search engine that will render the products, base on the value I type on the input.
With my code below, I tried that way but it seems that my logic isn't correct.
Could someone go through my code and check it out and can give me some insight afterward, please.
Thank you in advance.
import data from "./utils/data";
const App = () => {
const [searchValue, setSearchValue] = useState("");
const handleChange = (e) => {
setSearchValue(e.target.value);
};
return (
<div>
<SearchInput handleChange={handleChange} searchValue={searchValue} />
<Products data={data} searchValue={searchValue} />
</div>
);
};
const SearchInput = ({ searchValue, handleChange }) => {
return (
<div>
<input
type="text"
placeholder="Search specific item..."
value={searchValue}
onChange={handleChange}
/>
</div>
);
};
export default SearchInput;
function Products({ data, searchValue }) {
const [productsInfo, setProductsInfo] = useState([]);
useEffect(() => {
filteredProducts(data);
}, []);
const filteredProducts = (products) => {
if (searchValue.toLowerCase().trim() === "") {
setProductsInfo(products);
} else {
const seekedItem = productsInfo.filter(
(product) =>
product.name.toLowerCase().trim().includes(searchValue) ===
searchValue.toLowerCase().trim()
);
setProductsInfo(seekedItem);
}
};
const productsData =
productsInfo.length <= 0 ? (
<div>Loading...</div>
) : (
<div>
{productsInfo.map((product, index) => {
return (
<div
key={index}
style={{ backgroundColor: "grey", maxWidth: "300px" }}
>
<h4>{product.name}</h4>
<p>{product.category}</p>
<p> {product.price} </p>
<hr />
</div>
);
})}
</div>
);
return productsData;
}
export default Products;
const data = [
{
category: "Sporting Goods",
price: "$49.99",
stocked: true,
name: "Football",
},
{
category: "Sporting Goods",
price: "$9.99",
stocked: true,
name: "Baseball",
},
{
category: "Sporting Goods",
price: "$29.99",
stocked: false,
name: "Basketball",
},
{
category: "Electronics",
price: "$99.99",
stocked: true,
name: "iPod Touch",
},
{
category: "Electronics",
price: "$399.99",
stocked: false,
name: "iPhone 5",
},
{ category: "Electronics", price: "$199.99", stocked: true, name: "Nexus 7" },
];
export default data;
If you return empty array in second params in useEffect This function fired only once. Try that:
useEffect(() => {
filteredProducts(data);
}, [searchValue]);
.includes return true or false (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/includes)
Try that:
const filteredProducts = (products) => {
if (searchValue.toLowerCase().trim() === "") {
setProductsInfo(products);
} else {
const seekedItem = productsInfo.filter(
(product) =>
product.name.toLowerCase().trim().includes(searchValue)
);
setProductsInfo(seekedItem);
}
};

In the following code How do I change code so it shows the lent details of the corresponding name when I click the notes.name button?

https://codesandbox.io/s/react-example-m9l6j?fontsize=14
I am new to react can you please show working code in codesandbox, thanks in advance
In the following code How do I change code so it shows the lent details of the corresponding name when I click the notes.name button?
function Todo() {
let notes = [
{
id: 1,
name: "Brad",
lent: [{ id: 1, amount: 1000 }, { id: 2, amount: 2000 }]
},
{
id: 2,
name: "John",
lent: [{ id: 1, amount: 3000 }, { id: 2, amount: 4000 }]
}
];
const [state, setState] = React.useState(false);
const handleClick = e => {
setState(!state);
console.log(e.target);
};
return (
<div>
{notes.map(note => (
<ul key={note.id}>
<button onClick={handleClick}>{note.name}</button>
</ul>
))}
{state &&
notes[0].lent.map((
mapper //how do I change index here?
) => (
<ul key={mapper.id}>
<li>{mapper.id}</li>
<li>{mapper.amount}</li>
</ul>
))}
</div>
);
}
Please check the solution here, https://codesandbox.io/s/react-example-8f0jy?fontsize=14.
I have tried to store the id as a reference when the user clicks on a button. And then try to filter the notes based on the id.
function Todo() {
let notes = [
{
id: 1,
name: "Brad",
lent: [{ id: 1, amount: 1000 }, { id: 2, amount: 2000 }]
},
{
id: 2,
name: "John",
lent: [{ id: 1, amount: 3000 }, { id: 2, amount: 4000 }]
}
];
const [id, setId] = React.useState(-1);
const handleClick = id => {
setId(id);
};
return (
<div>
{notes.map(note => (
<ul key={note.id}>
<button onClick={() => handleClick(note.id)}>{note.name}</button>
</ul>
))}
{id >= 0 &&
notes
.filter(note => note.id === id)[0]
.lent.map((
mapper //how do I change index here?
) => (
<ul key={mapper.id}>
<li>{mapper.id}</li>
<li>{mapper.amount}</li>
</ul>
))}
</div>
);
}

Resources