Home > Net >  React state, remove item in array after a while
React state, remove item in array after a while

Time:09-30

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.

CodePudding user response:

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

CodePudding user response:

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)
},[])
  • Related