显示旋转负载

Show spinning loading

目标:
当您按下按钮时,旋转条应在加载过程中显示。

问题:
您如何根据此源代码在这种情况下采用这种方法?

Stackblitz:
https://stackblitz.com/edit/react-ts-zwhxny

谢谢!


App.tsk

import React, { useEffect, useState } from 'react';
import { BrowserRouter as Router, Route, Routes, Navigate  } from 'react-router-dom';
import Home from './Home';
import Login from './Login';

const App: React.FC = () => {
  const [isAuthenticated, setIsAuthenticated] = useState<boolean>(false);

  useEffect(() => {
    console.log('Authentication state - ', isAuthenticated);
  }, [isAuthenticated]);

  const handle_login = () => {
    setIsAuthenticated(true);
  };

  const handle_logout = () => {
    setIsAuthenticated(false);
  };

  const authenticatedRoutes = (
    <React.Fragment>
      <Routes>
        <Route
          path="/home"
          element={<Home handle_logout={handle_logout} />}
        />
        <Route
          path="*"
          element={<Navigate to="/home" />}
        />     
      </ Routes>
  
    </React.Fragment>
  );

  const nonAuthenticatedRoutes = (
    <React.Fragment>
      <Routes>
        <Route 
          path="/login"
          element={<Login handle_login={handle_login} />}
        />
      <Route
          path="*"
          element={<Navigate to="/login" />}
      />       
      </ Routes>
      <br />
      <br />
      <br />
      <br />
    </React.Fragment>
  );

  return (
    <Router>
      {/* <IonRouterOutlet> */}

      {isAuthenticated ? authenticatedRoutes : nonAuthenticatedRoutes}

      {/* </IonRouterOutlet> */}
    </Router>
  );
};

export default App;

handle_login.tsx

import axios from 'axios';

export const handle_loginnn = async () => {
  const login = {
    username: 'userAlpha',
    password: '123',
  };

  // must use async for token
  const response = await axios.get(AlphaClientLogin, login);
  sessionStorage.setItem('auth', response.data.token);

  return response.data.token;
};

Home.tsx

import React from 'react';

interface HomeProps {
  handle_logout: () => void;
}

const Home: React.FC<HomeProps> = (props) => {
  return (
    <React.Fragment>
      <header>
        {/* <h2>Home </h2> */}

        <button slot="end" onClick={props.handle_logout}>
          {' '}
          Logout{' '}
        </button>
      </header>
      <title> Home </title>
      <div className="container">
        <strong>Home page</strong>
        <p>Click logout on the titlebar to logout </p>
      </div>
    </React.Fragment>
  );
};

export default Home;

Login.tsx

import React, { useState } from 'react';

interface LoginProps {
  handle_login: () => void;
}

const Login: React.FC<LoginProps> = (props) => {
  const [loading, setLoading] = useState<boolean>(false);

  return (
    <React.Fragment>
      <title> Login </title>
      <div className="container">
        <strong>login page</strong> <br />
        <br />
        <button onClick={props.handle_login} disabled={loading}>
          {loading && (
            <span className="spinner-border spinner-border-sm"></span>
          )}
          <span>Login</span>
        </button>{' '}
        <br />
        <div id="asdf"></div>
      </div>
    </React.Fragment>
  );
};

export default Login;

Login.tsx

import React, { useState } from 'react';
import './style.css';

interface LoginProps {
  handle_login: () => void;
}

const Login: React.FC<LoginProps> = (props) => {
  const [loading, setLoading] = useState<boolean>(false);

  function handle_login(e) {
    setTimeout(() => {
      props.handle_login();
    }, 5000);
    setLoading(true);
  }

  return (
    <React.Fragment>
      <title> Login </title>
      <div className="container">
        <strong>login page</strong> <br />
        <br />
        <button onClick={handle_login} disabled={loading}>
          {loading && (
            <span style={{ marginRight: '5px' }}>
              <span className="lds-ring">
                <div></div>
                <div></div>
                <div></div>
                <div></div>
              </span>
            </span>
          )}
          <span>Login</span>
        </button>{' '}
        <br />
        <div id="asdf"></div>
      </div>
    </React.Fragment>
  );
};

export default Login;

style.css

h1,
p {
  font-family: Lato;
}

button {
  min-height: 30px;
}

.lds-ring {
  display: inline-block;
  position: relative;
  width: 20px;
  height: 20px;
}
.lds-ring div {
  box-sizing: border-box;
  display: block;
  position: absolute;
  width: 20px;
  height: 20px;
  margin: 2px;
  border: 3px solid #fff;
  border-radius: 50%;
  animation: lds-ring 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;
  border-color: #fff transparent transparent transparent;
}
.lds-ring div:nth-child(1) {
  animation-delay: -0.45s;
}
.lds-ring div:nth-child(2) {
  animation-delay: -0.3s;
}
.lds-ring div:nth-child(3) {
  animation-delay: -0.15s;
}
@keyframes lds-ring {
  0% {
    transform: rotate(0deg);
  }
  100% {
    transform: rotate(360deg);
  }
}