skip to Main Content

I have an array of items which I map in my UI:

let arr = [1, 2, 3, 4, 5, 6, 7... n]

Say I want to map each item as a JSX paragraph BUT, I want to be able to change the order of each element within the array by calling a function swap which changes the value of arr (assume that arr is stored in a redux slice and automatically updates after calling function swap.

For example, if I call the function swap(3, "up"), then the item 3 will be swapped with the item 2 and the result will be: [1, 3, 2, 4, 5, 6, 7... n]. Conversely, if I swap the other direction – down, the item will swap with its successor.

I also have a delete function which will remove the item altogether and all the items after it will get bumped up by one space: delete(4) will result in [1, 2, 3, 5, 6, 7...n].

This logic is done, it all works and I have observed that the changes apply perfectly in the UI. The problem is that I need to somehow inform the user that this happened. For example, a transition or animation so that the action is not instant.

Here is what I have written:

const lectures = useSelector((state: RootState) => state.course.lectures) 
/* lectures always is sorted by its positional index which changes with swap 
(swapping two elements) and delete (deletes current and bumps up all its 
successors) */ 

const delete = (lecture) => { 
    /* a dispatch to an action that will result in deleting an item from the lectures array */
}

const swap = (lecture, direction) => { 
    /* a dispatch to an action that will result in swapping the given lecture with its pred/succ depending on the direction. */
}

return (
  <div>
    {
      lectures.map(lect => (
        <span>
            <h3>{lect.position_index}</h3>
            <p>{lect.title}</p>
            <button onClick={e => swap(lect, "up")}>UP</button>
            <button onClick={e => swap(lect, "down")}>DOWN</button>
            <button onClick={e => delete(lect)}>DELETE</button>
        </span>
      )
    }
  </div>
)

The changes apply but they are instantaneous. I want to add a transition of some sort – 200 or 300 milliseconds transition disappearing effect on delete and tbh anything for the swapping it doesn’t matter as long as the user knows that it happens.
I dont want the users to end up deleting the wrong lecture because they thought that their delete didn’t take effect.

I apologize for any misused terminology.

2

Answers


  1. Chosen as BEST ANSWER

    Okay, so it turns out that I cannot solve this with any libraries or tools - I had to implement my own solution as I expected.

    The way I did this is by having two states in the parent component where I render my lectures - deleting and swapping:

    const [deleting, setDeleting] = useState<number | null>(null)
    const [swapping, setSwapping] = useState<number | null>(null)
    

    Whenever I run a delete or swap I basically set these states with the lecture id and put the dispatch in a timeout:

    const delete = lecture => {
        setDeleting(lectute.id)
        setTimeout(() => {
            dispatch(deleteLecture(lecture))
        }, 500)
    } // Same code for the Swap function with a different dispatch more or less
    

    In my render I have basically the same code with a minor detail - conditioanl class name for when it is being deleted:

    <div>
      {
        lectures.map(lect => (
          <span className={`transition ${deleting === lect.id ? "delete" : ""} ${swapping === lect.id ? "swap" : ""}`}>
            <h3>{lect.position_index}</h3>
            <p>{lect.title}</p>
            <button onClick={e => swap(lect, "up")}>UP</button>
            <button onClick={e => swap(lect, "down")}>DOWN</button>
            <button onClick={e => delete(lect)}>DELETE</button>
          </span>
        )
      }
    </div>
    

    Finally, I have two useEffects which listen on changes to deleting and swapping states and update their state properly:

    useEffect(() => {
        if (deleting === null) return
        setTimeout(() => setDeleting(null), 2000)
    }, [deleting])
    
    useEffect(() => {
        if (swapping === null) return
        setTimeout(() => setSwapping(null), 2000)
    }, [swapping])
    

    I made it 2000ms assuming that it will not take more than 1500ms for the dispatch to resolve which currently takes up to 800ms on slow internet in production environment under stress conditions.


  2. Try changing css styles with useState, not sure if it’s 100% what you’re looking for, but it definitely works.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search