Price filtering ascending & descending React js - reactjs

I tried to set up the functionality to filter my product in an ascending or descending manner.
If you check my code below in order to access the price of each product I tried to map through the products, remove then the dollar sign and sort it to ascending and finally set the new state of the products.
But now I feel confused now because I have the sorted array but no more the entire product when trying to set the new state of the product ??
Thank you for helping
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;
const App = () => {
const [searchValue, setSearchValue] = useState("");
const [productsInfo, setProductsInfo] = useState([]);
const handleChange = (e) => {
setSearchValue(e.target.value);
};
const selectedChangeFilter = (e) => {
if (e.target.value === "sporting goods") {
const sportingGoods = data.filter(
(product) => product.category === "Sporting Goods"
);
setProductsInfo(sportingGoods);
}
if (e.target.value === "electronics") {
const electronicsGoods = data.filter(
(product) => product.category === "Electronics"
);
setProductsInfo(electronicsGoods);
}
if (e.target.value === "lowest price") {
const lowestPriceGoods = data
.map((product) => product.price.substr(1))
.sort((a, b) => a - b);
console.log(lowestPriceGoods);
setProductsInfo(lowestPriceGoods);
}
if (e.target.value === "all") {
setProductsInfo(data);
}
};
const searchProducts = (products) => {
if (searchValue.toLowerCase().trim() === "") {
setProductsInfo(products);
} else {
const seekedItem = productsInfo.filter(
(product) =>
product.name.toLowerCase().trim().includes(searchValue) ||
product.category.toLowerCase().trim().includes(searchValue)
);
setProductsInfo(seekedItem);
}
};
return (
<div>
<SearchInput
handleChange={handleChange}
searchValue={searchValue}
selectedChangeFilter={selectedChangeFilter}
/>
<Products
data={data}
searchValue={searchValue}
productsInfo={productsInfo}
searchProducts={searchProducts}
/>
</div>
);
};
export default App;

Try this improved code
const selectedChangeFilter = (e) => {
const { value } = e.target
if (value === "sporting goods") {
const sportingGoods = data.filter(
(product) => product.category === "Sporting Goods"
);
setProductsInfo(sportingGoods);
}
if (value === "electronics") {
const electronicsGoods = data.filter(
(product) => product.category === "Electronics"
);
setProductsInfo(electronicsGoods);
}
if (value === "lowest price") {
const lowestPriceGoods = data.sort((el1,el2) => el1.price.localeCompare(el2.price, undefined, {numeric: true}));
setProductsInfo([...lowestPriceGoods]);
}
if (value === "highest price") {
const highestPriceGoods = data.sort((el1,el2) => el2.price.localeCompare(el1.price, undefined, {numeric: true}));
setProductsInfo([...highestPriceGoods]);
}
if (value === "all") {
setProductsInfo(data);
}
};

You can use string#localeCompare to sort your array based on the number by using numeric property.
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" }, ];
data.sort((a,b) => a.price.localeCompare(b.price, undefined, {numeric: true}));
console.log(data);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Related

how to show only the result of the selection?

my current code shows a complete list of clinics, when in the selector I choose a province, it shows me the clinics located in that province, what I would like is not to show the complete list of clinics at the beginning but only show the result when filtering by province. That is to say, when starting the application that only the selection is seen and once the province is selected, the results will be shown.
import React, { useState, useEffect } from 'react'
import Select, { SingleValue } from 'react-select'
import { getClinic } from '../../api/drupalAPI'
import {Clinic} from '#icofcv/common';
export const SearchFilterClinics = () => {
////filter
type OptionType = {
value: string;
label: string;
};
const provincesList: OptionType[] = [
{ value: 'Todos', label: 'Todos' },
{ value: 'Alava/Araba', label: 'Alava/Araba' },
{ value: 'Albacete', label: 'Albacete' },
{ value: 'Alicante', label: 'Alicante' },
{ value: 'Almería', label: 'Almería' },
{ value: 'Avila', label: 'Avila' },
{ value: ' Badajoz', label: ' Badajoz' },
{ value: 'Islas Baleares', label: 'Islas Baleares' },
{ value: 'Barcelona', label: 'Barcelona' },
{ value: 'Burgos', label: 'Burgos' },
{ value: 'Cáceres', label: 'Cáceres' },
{ value: 'Cádiz', label: 'Cádiz' },
{ value: 'Castellón', label: 'Castellón' },
{ value: 'Ciudad Real', label: 'Ciudad Real' },
{ value: 'Córdoba', label: 'Córdoba' },
{ value: 'A Coruña/La Coruña', label: 'A Coruña/La Coruña' },
{ value: 'Cuenca', label: 'Cuenca' },
{ value: 'Gerona/Girona', label: 'Gerona/Girona' },
{ value: 'Granada', label: 'Granada' },
{ value: 'Guadalajara', label: 'Guadalajara' },
{ value: 'Gipuzkoa/Guipuzcoa', label: 'Gipuzkoa/Guipuzcoa' },
{ value: 'Huelva', label: 'Huelva' },
{ value: 'Huesca', label: 'Huesca' },
{ value: 'Jaen', label: 'Jaen' },
{ value: 'León', label: 'León' },
{ value: 'Lérida/Lleida', label: 'Lérida/Lleida' },
{ value: 'La Rioja', label: 'La Rioja' },
{ value: 'Lugo', label: 'Lugo' },
{ value: 'Madrid', label: 'Madrid' },
{ value: ' Málaga', label: ' Málaga' },
{ value: 'Murcia', label: 'Murcia' },
{ value: 'Navarra', label: 'Navarra' },
{ value: 'Orense/Ourense', label: 'Orense/Ourense' },
{ value: 'Asturias', label: 'Asturias' },
{ value: 'Palencia', label: 'Palencia' },
{ value: 'Las Palmas', label: 'Las Palmas' },
{ value: 'Pontevedra', label: 'Pontevedra' },
{ value: 'Salamanca', label: 'Salamanca' },
{ value: 'S.C.Tenerife', label: 'S.C.Tenerife' },
{ value: 'Cantabria', label: 'Cantabria' },
{ value: 'Segovia', label: 'Segovia' },
{ value: ' Sevilla', label: ' Sevilla' },
{ value: 'Soria', label: 'Soria' },
{ value: 'Tarragona', label: 'Tarragona' },
{ value: 'Teruel', label: 'Teruel' },
{ value: 'Toledo', label: 'Toledo' },
{ value: 'Valencia', label: 'Valencia' },
{ value: 'Valladolid', label: 'Valladolid' },
{ value: 'Bizkaia/Vizcaya', label: 'Bizkaia/Vizcaya' },
{ value: 'Zamora', label: 'Zamora' },
{ value: 'Zaragoza', label: 'Zaragoza' },
{ value: 'Ceuta', label: 'Ceuta' },
{ value: 'Melilla', label: 'Melilla' },
]
const [clinicList, setClinicList] = useState<Clinic[]>([]);
const [clinicListFilteredSelect, setClinicListFilteredSelect] = useState<Clinic[]>([]);
const [filterSelectClinic, setFilterSelectClinic] = useState<SingleValue<OptionType>>(provincesList[0]);
const fetchClinicList = async () => {
getClinic().then((response)=>{
console.log(response)
setClinicList(response);
setClinicListFilteredSelect(response)
}).catch ( (error) => {
console.error(error);
throw error;
});
}
const handleChangeSelect = (provinceList: SingleValue<OptionType>) =>{
console.log(provinceList)
setFilterSelectClinic(provinceList);
filterSelect(provinceList );
}
const filterSelect=(termSearch)=>{
const resultFilterSelect = clinicList.filter((element) => {
if(element.province?.toString().toLowerCase().includes(termSearch.value.toLowerCase() )
){
return element;
}
});
setClinicListFilteredSelect(resultFilterSelect);
}
useEffect (() => {
fetchClinicList();
}, []);
return (
<>
<div>
<h1>Encuentra tu clínica</h1>
</div>
<div>
<Select
defaultValue={filterSelectClinic}
options={provincesList}
onChange={handleChangeSelect}
/>
{
clinicListFilteredSelect.map((clinic) => (
<div>
<div>{clinic.title}</div>
<div>{clinic.propsPhone}</div>
<div>{clinic.mobile}</div>
<div>{clinic.email}</div>
<div>{clinic.province} </div>
<div>{clinic.registry}</div>
</div>
))
}
</div>
</>
)
}
You're setting clinicListFilteredSelect in your useEffect with an empty dependancy array. This means when your component mounts it will set clinicListFilteredSelect to the response of your API call.
If you instead want to only show the response when filterting by clinics, you need to move this call to the event handler and remove the useEffect.
Something like:
const handleChangeSelect = async (provinceList: SingleValue<OptionType>) => {
getClinic().then((response) => {
setClinicList(response);
setClinicListFilteredSelect(response)
setFilterSelectClinic(provinceList);
filterSelect(provinceList );
}).catch ((error) => {
console.error(error);
throw error;
});
}

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);
}
};

React JS, When clicked one option, other options are also being selected

Below is Options component It generates bunch of options The problem is that when I click One option Others are also being selected. I know why this is happening but I couldnt solve it
const InterestGenerator = () => {
const interest_emojis = [
{ name: "Comedy" },
{ name: "Comedy" },
{ name: "Comedy" },
{ name: "Comedy" },
{ name: "Comedy" },
{ name: "Comedy" },
{ name: "Comedy" },
{ name: "Comedy" },
{ name: "Comedy" },
{ name: "Comedy" },
{ name: "Comedy" },
{ name: "Comedy" },
];
const [selected, setSelected] = useState(false);
const handleClick = (e) => {
selected ? setSelected(false) : setSelected(true);
};
return (
<div className="interests_options">
{interest_emojis.map((interest) => {
return (
<div
className={`interest ${selected ? " interest_selected" : ""}`}
onClick={handleClick}
>
{!selected && (
<img
className="interest_emoji"
src={require("../assets/emoji_" + interest.name + ".png")}
alt="comedy_emoji"
/>
)}
{selected && <DoneIcon />}
<span>{interest.name}</span>
</div>
);
})}
</div>
);
};
export default InterestGenerator;
enter image description here
As you can see you have a single selected state in the component. Hence even if you click once it's set for everybody.
The solution would be to have a component each having their own state that is doing what you're doing and rendering a list of those components.
Something like this will work :
This is the solo component :
const interestEmojiComponent = ({name})=>{
const [selected, setSelected] = useState(false);
const handleClick = (e) => {
selected ? setSelected(false) : setSelected(true);
};
return (
<div
className={`interest ${selected ? " interest_selected" : ""}`}
onClick={handleClick}
>
{!selected && (
<img
className="interest_emoji"
src={require("../assets/emoji_" + name + ".png")}
alt="comedy_emoji"
/>
)}
{selected && <DoneIcon />}
<span>{name}</span>
</div>
);
}
And this is the generator Component :
const InterestGenerator = () => {
const interest_emojis = [
{ name: "Comedy" },
{ name: "Comedy" },
{ name: "Comedy" },
{ name: "Comedy" },
{ name: "Comedy" },
{ name: "Comedy" },
{ name: "Comedy" },
{ name: "Comedy" },
{ name: "Comedy" },
{ name: "Comedy" },
{ name: "Comedy" },
{ name: "Comedy" },
];
return(
<div className="interests_options">
{interest_emojis.map((interest) => <InterestEmojiComponent name={interest.name}/>)}
</div>
)
}
You are using just one selected state for all options which lead to your unexpected behavior. The solution here is to keep the selected state for each option
const [interest_emojis, set_interest_emojis] = useState([
{ name: "Comedy", selected: false },
{ name: "Comedy", selected: false },
{ name: "Comedy", selected: false },
{ name: "Comedy", selected: false },
{ name: "Comedy", selected: false },
{ name: "Comedy", selected: false },
{ name: "Comedy", selected: false },
{ name: "Comedy", selected: false },
{ name: "Comedy", selected: false },
{ name: "Comedy", selected: false },
{ name: "Comedy", selected: false },
{ name: "Comedy", selected: false }
]);
const handleClick = (index) => {
const arr = [...interest_emojis];
arr[index].selected = !arr[index].selected;
set_interest_emojis(arr);
};
Demo

How to use spread operator to update array inside an object?

What the fetch returns is a list of items. I want to add those into state.
const [state, setState] = useState({
list: {
items: [],
}
});
fetch('http://example.com/list/')
// GET response: [{ name: 'foo' }, { name: 'bar' }, { name: 'baz' }]
.then((resList) => resList.json())
.then((list) => {
list.forEach(({ name }) => {
const itemUrl = `https://example.com/list/${name}`;
fetch(itemUrl)
// GET responses:
// { name: 'foo', desc: '123' }
// { name: 'bar', desc: '456' }
// { name: 'baz', desc: '789' }
.then((itemRes) => itemRes.json())
.then((item) => {
setState((prevState) => ({
...prevState,
list: {
items: [...state.list.items, item]
},
});
})
})
}
})
console.log(state);
// result: [{ name: 'baz', desc: '789' }]
// but wanted: [{ name: 'foo', desc: '123' }, { name: 'bar', desc: '456' }, { name: 'baz', desc: '789' }]
In your case no need to use prevState in setState.
I prepared an example for you. Just be careful at using hooks.
https://codesandbox.io/s/recursing-wood-4npu1?file=/src/App.js:0-567
import React, { useState } from "react"
import "./styles.css"
export default function App() {
const [state, setState] = useState({
list: {
items: [
{ name: "foo", desc: "123" },
{ name: "bar", desc: "456" },
],
},
})
const handleClick = () => {
setState(() => ({
list: {
items: [...state.list.items, { name: "baz", desc: "789" }],
},
}))
}
return (
<div className="App">
<button onClick={handleClick}>Click Me </button>
<hr />
{JSON.stringify(state)}
</div>
)
}
You can't directly access the callback for useState hooks. This is how you can update state after fetching the data:
setState({
...state,
list: {
items:[...state.list.items, item]
},
});

Resources