1

I'm trying to build a toaster component with React's hook api but I can't figure out how to make it behave correctly. Right now all toasts disappear, 1 is removed, the rest appears and the cycle repeats.

Ideally the oldest Toast notification disappears while the rest is clearly visible.

Link to REPL: https://repl.it/@nikolaipaul/FabulousHideousMicrobsd

Here is the code for the Toast component:

const Toast = ({ id, message, remove }) => {
    const [isShown, setIsShown] = React.useState(true)

    React.useEffect(() => {
        if (isShown) {
            const timeout = setTimeout(() => {
                console.log(`hiding toast id ${id}`)
                setIsShown(false)
            }, 2000)

            return () => clearTimeout(timeout)
        }
    })

    return (
        <CSSTransition 
          classNames="toast" 
          unmountOnExit 
          mountOnEnter 
          appear 
          in={isShown} 
          timeout={300} 
          onExited={() => remove(id)}>
            <div className="toast">{message}</div>
        </CSSTransition >
    )
}

and the hook that manages the list of toasts:

export const useToast = () => {
    const [toasts, setToasts] = React.useState([])

    const add = message => {
        const id = Math.random().toString(36).substr(2, 9)

        const toast = {
            id,
            message,
            remove,
        }

        console.log(`adding toast id ${id}`)
        setToasts(toasts => toasts.concat(toast))
    }

    const remove = id => {
        console.log(`removing toast id ${id}`)

        setToasts(toasts => toasts.filter(toast => toast.id !== id))
    }

    const Toaster = () => {
        const toaster =
          <div style={{ position: "fixed", right: 0, top: 0 }}>
            {toasts.map(toast => <Toast {...toast} key={toast.id} />)}
          </div>

        return ReactDOM.createPortal(toaster, document.getElementById("toasts"))
    }

    return [Toaster, add]
}
apokryfos
  • 38,771
  • 9
  • 70
  • 114
Megamind
  • 251
  • 2
  • 16
  • While the repl.it example is good. It would also be good if you included the code itself in this question. It's not that long a code so I don't see any reason why you shouldn't do that – apokryfos Sep 06 '19 at 11:25
  • thanks, I added the code and more description – Megamind Sep 06 '19 at 11:31
  • Modeling it as use{Hook} just seems overall sketchy. I tried mounting the toast container (Toaster) with a context provider and it seems to work that way. Everything is rendered as it should and the dom is cleaned appropriately. @apokryfos How to close this? You guys haven't even given this post a couple minutes to rest. You immediately put it on hold. Instead of helping, you just blocked this whole post. SO has it's rules but to me this seems like antisocial behaviour. – Megamind Sep 06 '19 at 12:50
  • Two changes:- 1) Remove `appear` prop. 2) Use `onExit` instead of `onExited`; ` remove(id)} >` – tarzen chugh Sep 06 '19 at 12:53

0 Answers0