user6287681
user6287681

Reputation:

React state, remove item in array after a while

I'm facing a problem, I have a React state which is an array.

When an item is added to the array with setState, I would like to delete it after for example five seconds.

Something like :

const {messages, setMessages} = useState([])

useEffect(() => {
    const timer = setTimeout(() => {
        setMessages(arr => arr.splice(i, 1))
    }, 5000)

    return () => clearTimeout(timer)
})

Where i is the index of the item to delete.

As a concrete example: I click every second in a button, this add an item to the array. After 5 seconds, the first item is deleted. After 6 seconds, the second item is deleted. etc...

Thanks for your help.

Upvotes: 2

Views: 1905

Answers (2)

WebbH
WebbH

Reputation: 2422

You could set each item in the array as an object with a timeRemaining property and then use setInterval to reduce the time every second until it eventually hits 0, at which point you would delete the item.

useEffect(()=>{
  const interval = setInterval(()=>{
    setMessages(prev=>prev.filter(i=>i.timeRemaining>0).map((item)=>{
      return {
        ...item, timeRemaining: item.timeRemaining - 1
      }
    }))
  },1000)
  return ()=> clearInterval(interval)
},[])

Upvotes: 0

Drew Reese
Drew Reese

Reputation: 203099

Array.prototype.splice mutates the array in place, meaning the messages state array reference never changes and React bails out of rerendering.

Array.prototype.splice

The splice() method changes the contents of an array by removing or replacing existing elements and/or adding new elements in place.

Bailing out of a state update

If you update a State Hook to the same value as the current state, React will bail out without rendering the children or firing effects. (React uses the Object.is comparison algorithm.)

You can use Array.prototype.filter to shallow copy the previous messages array into a new reference, except for the element at the specified matching index.

useEffect(() => {
  const timer = setTimeout(() => {
    setMessages(arr => arr.filter((_, index) => index !== i)) // *
  }, 5000);

  return () => clearTimeout(timer);
}, []); // <-- don't forget dependency array!

* assumes i is defined in scope

Upvotes: 2

Related Questions