When is the cleanup function triggered when using useEffect hook with dependencies?

The explanation provided by @Powell Ye is good however there a bit of erroneous information specifically when speaking about re-renders (e.g. when props change)

consider some simple component with the following

    useEffect( () => {
        console.log('Effect is applied')
        //some logic
        return () => {
            console.log('cleaning up')
            //cleanup logic
        }
    })
    return (<>
        {console.log('rendering...')}
     </>)

say the props passed in changes you might think it goes as such

  1. 'cleaning up'
  2. new props
  3. 'rendering...'
  4. 'Effect is applied'

However, the following actually occurs

  1. new props
  2. 'rendering...'
  3. 'cleaning up'
  4. 'Effect is applied'

That is, the clean up function runs AFTER the new render/painting but BEFORE the 'new' effects are applied, the docs can be a bit ambigious about this

the previous effect is cleaned up before executing the next effect

This is done for performance reasons => so that rendering is not delayed ( it can be frustrating at times for me too )