J. Doe
J. Doe

Reputation: 125

Update array of object in React useState

I have a class ListItem which is a list of Item. It got some function like setItem that update an item in the list and addItem that add an item and filterItem that set visible

Item is an object that looks like {name,number,discount,visible}

I have a view ListItemView with a pseudo code like this

export default function ListItemView() {

    const [items, setItems] = useState([])

    useEffect(() => {
        setItems(new ListItem(getItems()))
    }, [])
    
    function toggleChange(f,newF){
        setItems((current) => current.setItem(f,newF))
    }

    function filter(search){
        setItems(Items.filterItem({search}))
    }

    return (
        <>
            <button onClick={() => setItems(items.addItem())}> ADD Item</button>
            <input onChange={(e) => filter(e.target.value)} />
            {items.items.map((Item) =>
               !item.visible && item.visible !== undefined  ? null :
               <div key={Item.id}>
                  <ItemLine f={item} toggleChange={toggleChange} />
               </div>
            )}
        </>
    )
}

And ItemLine is just a component that display inputs with the datas of my item

So there is my questions :

Thanks for your expertise :)

Upvotes: 1

Views: 2995

Answers (1)

Shubham Khatri
Shubham Khatri

Reputation: 281606

To update my items, am I forced to use setItems everytimes ? Because it's causing the full rerender of the page, that's quite dumb for me because when we are just setting 1 data in one object of an entire list ?

Yes you need to call setItems to update your state even if it is to add one element or to update one.

However you can optimise on re-renders by converting your mapped values to components and using React.memo to avoid re-renders .

function Item = React.memo(({item, toggleChange}) => {
   return !item.visible && item.visible !== undefined  ? null :
        <div key={Item.id}>
                  <ItemLine f={item} toggleChange={toggleChange} />
         </div>
})
export default function ListItemView() {

    const [items, setItems] = useState([])

    useEffect(() => {
        setItems(new ListItem(getItems()))
    }, [])

    // using useCallback to have only one instaance of toggleChange being created even on re-renders 
    const toggleChange = useCallback(function toggleChange(f,newF){
        setItems((current) => current.setItem(f,newF))
    }, []);

    function filter(search){
        setItems(Items.filterItem({search}))
    }

    return (
        <>
            <button onClick={() => setItems(items.addItem())}> ADD Item</button>
            <input onChange={(e) => filter(e.target.value)} />
            {items.items.map((Item) =>
               <Item key={item.id} item={item} toggleChange={toggleChange}/>
            )}
        </>
    )
}

My filter function is quick when I'm typing (to filter on my list), but it's pretty slow when I have to reshow every items in my list, with 300 items it would be unusable, how can I change this ?

If you are rendering large lists, you should aim towards virtualising those, i.e rendering only items that are in the view. react-window and react-virtualized are popular libraries that you can explore for that.

Upvotes: 2

Related Questions