I'm having a performance issue in React.
I have a list (ItemList
), on which I want to delete some of the items (Item
).
I'm using a filter
methode to do so, setting the newly filtered list in the App
parent component.
The items
State
in App
is updated via the setItems
function and goes back to ItemList
.
EDIT
The items
state
is an Array
of Object
, like this :
[
{name: "NAME 1", reference: "REF 1", description: "LOREM IPSUM"},
{name: "NAME 2", reference: "REF 2", description: "LOREM IPSUM"},
{name: "NAME 3", reference: "REF 3", description: "LOREM IPSUM"},
]
It works well, the thing is that it re-renders all the ItemList
's Item
s, namely, the ones which were not deleted, which is superfluous.
I also tried a variant wrapping the returned JSX from Item
in useMemo
, but this time, the deleteItem function works only once, and does not delete the right Item
anyway.
here's the code :
App.js
import React, { useState} from "react";
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
import ItemList from "./itemList"
function App() {
const [items, setItems] = useState([])
const deleteItem = (newItem) => {
const newItemList = items.filter(item=> item.reference !== newItem.reference)
setItems(newItemList)
}
return (
<>
<div className="App">
<Router>
<div id="wrapper">
<Switch>
<Route path = "/itemList" exact render = {() =>
<ItemList
data={items}
deleteItem ={deleteItem }
></ItemList>}>
</Route>
</Switch>
</div>
</Router>
</div>
{console.log("App")}
</>
);
}
export default App;
itemList.js
import React, { useEffect, useState } from "react";
import Item from "./item";
const ItemList= (props) => {
const [itemList, setItemList] = useState([])
//useffect to relaunch the list generation if props.data - the item list state in App - changes
useEffect(() => {
const newList = []
props.data.forEach((item, index) => {
newList.push(
<Item
deleteItem={props.deleteItem}
key={index}
item={item}
></Item>
)
})
setItemList(newList)
}, [props.data])
return (
<>
<div id="itemList">
{itemList}
</div>
{console.log("Item List")}
</>
)
};
export default ItemList;
item.js
import React from "react";
const Item = (props) => {
const handleDeleteItem = (item) => {
props.deleteItem(item)
}
return (
<>
{console.log("Item Line")}
<div className="ItemLine">
<table>
<tbody>
<tr>
<th>
<div onClick={() => props.deleteItem(props.item)}>
{props.item.name} - {props.item.reference} - {props.item.description}
</div>
</th>
</tr>
</tbody>
</table>
</div>
</>
)
}
export default Item;
item.js (Variant with useMemo)
import React, { useMemo } from "react";
const Item = (props) => {
const handleDeleteItem = (item) => {
props.deleteItem(item)
}
const itemLine = useMemo(() => {
return (
<>
{console.log("Item Line")}
<div className="ItemLine">
<table>
<tbody>
<tr>
<th>
<div onClick={() => props.deleteItem(props.item)}>
{props.item.name} - {props.item.reference} - {props.item.description}
</div>
</th>
</tr>
</tbody>
</table>
</div>
</>
)
}, [])
return (
<>
{itemLine()}
</>
)
}
export default Item;
CodePudding user response:
when updating the state you need to spread the previous state first before you update it
const deleteItem = (newItem) => {
const newItemList = items.filter(item=> item.reference !== newItem.reference)
setItems(prev => (...prev, newItemList))
}
CodePudding user response:
when updating the state you need to spread the previous state first before you update it
and depends of your type you must return array or object spreat operator opened previous array or object and then you was add new data setItems(prev => [...prev, newItemList])