Sfoglia il codice sorgente

[web] Add a delay before showing loading spinner while lazy-loading React components (#6262)

GitOrigin-RevId: a77d11e980103de31a5bf1a19391874bea70cfec
Alf Eaton 4 anni fa
parent
commit
d1e3ce8225

+ 26 - 2
services/web/frontend/js/shared/components/loading-spinner.js

@@ -1,14 +1,38 @@
 import { useTranslation } from 'react-i18next'
 import { useTranslation } from 'react-i18next'
 import Icon from './icon'
 import Icon from './icon'
+import { useEffect, useState } from 'react'
+import PropTypes from 'prop-types'
 
 
-function LoadingSpinner() {
+function LoadingSpinner({ delay = 500 }) {
   const { t } = useTranslation()
   const { t } = useTranslation()
+
+  const [show, setShow] = useState(false)
+
+  useEffect(() => {
+    const timer = window.setTimeout(() => {
+      setShow(true)
+    }, delay)
+
+    return () => {
+      window.clearTimeout(timer)
+    }
+  }, [delay])
+
+  if (!show) {
+    return null
+  }
+
   return (
   return (
     <div className="loading">
     <div className="loading">
       <Icon type="fw" modifier="refresh" spin />
       <Icon type="fw" modifier="refresh" spin />
-      {`  ${t('loading')}…`}
+      &nbsp;
+      {t('loading')}…
     </div>
     </div>
   )
   )
 }
 }
 
 
+LoadingSpinner.propTypes = {
+  delay: PropTypes.number,
+}
+
 export default LoadingSpinner
 export default LoadingSpinner

+ 20 - 1
services/web/test/frontend/features/chat/components/chat-pane.test.js

@@ -12,8 +12,21 @@ import {
   cleanUpContext,
   cleanUpContext,
 } from '../../../helpers/render-with-context'
 } from '../../../helpers/render-with-context'
 import { stubMathJax, tearDownMathJaxStubs } from './stubs'
 import { stubMathJax, tearDownMathJaxStubs } from './stubs'
+import sinon from 'sinon'
 
 
 describe('<ChatPane />', function () {
 describe('<ChatPane />', function () {
+  beforeEach(function () {
+    this.clock = sinon.useFakeTimers({
+      toFake: ['setTimeout', 'clearTimeout', 'setInterval', 'clearInterval'],
+    })
+  })
+
+  afterEach(function () {
+    this.clock.runAll()
+    this.clock.restore()
+    fetchMock.reset()
+  })
+
   const user = {
   const user = {
     id: 'fake_user',
     id: 'fake_user',
     first_name: 'fake_user_first_name',
     first_name: 'fake_user_first_name',
@@ -78,10 +91,16 @@ describe('<ChatPane />', function () {
   })
   })
 
 
   it('a loading spinner is rendered while the messages are loading, then disappears', async function () {
   it('a loading spinner is rendered while the messages are loading, then disappears', async function () {
-    fetchMock.get(/messages/, [])
+    fetchMock.get(/messages/, [], { delay: 1000 })
 
 
     renderWithChatContext(<ChatPane />, { user })
     renderWithChatContext(<ChatPane />, { user })
 
 
+    this.clock.tick(600) // wait for spinner to be displayed
+
+    await screen.findByText('Loading…')
+
+    this.clock.tick(1000) // wait for response to be received
+
     await waitForElementToBeRemoved(() => screen.getByText('Loading…'))
     await waitForElementToBeRemoved(() => screen.getByText('Loading…'))
   })
   })