AtomicCommit
AtomicCommit

Reputation: 39

How to set Loading when the button is clicked and show the result after timeout?

please help. I can't make the loading appear correctly. So whenever the user click Login or Logout, it should be Loading... first for 2 second, and then show the result whether the user is Login or not. Instead, my current result is it always loading and never ends.

Here's my code:

import React, { useState } from "react";
import "./App.css";

const App = () => {
  const [state, setState] = useState({
    user: "John Doe",
    isLogin: false,
    isLoading: false,
  });

  const handleClick = () => {
    setTimeout(() => {
      setState({
        isLoading: !state?.isLoading,
        user: state?.user,
        status: !state?.status,
        isLogin: !state?.isLogin,
      });
    }, 2000);
  };

  return (
    <>
      <div className="App">
        <h1>Practice makes perfect</h1>
        {state?.isLoading ? (
          <p>Loading...</p>
        ) : (
          <button onClick={() => handleClick()}>
            {state?.isLogin ? "Logout" : "Login"}
          </button>
        )}
        <p>{state?.isLogin ? `Hello ${state?.user}` : "Please Login"}</p>
      </div>
    </>
  );
};

export default App;

Thank you, sorry for bad english.

Upvotes: 0

Views: 1384

Answers (2)

Mostafa Kalantari Fard
Mostafa Kalantari Fard

Reputation: 304

You need a handler to change your isLoading state when user clicked on the button. So this code is what you need:

import React, { useState } from "react";
import "./App.css";

const App = () => {
  const [state, setState] = useState({
    user: "John Doe",
    isLogin: false,
    isLoading: false,
  });

  const handleLoading = () => {
    setTimeout(() => {
      setState({
        ...state,
        isLoading: false,
        isLogin: !state?.isLogin,
      });
    }, 2000);
  };

  const handleClick = () => {
    setTimeout(() => {
      setState({
        ...state,
        isLoading: !state?.isLoading,
        user: state?.user,
        status: !state?.status,
        isLogin: !state?.isLogin,
      });
      handleLoading();
    }, 2000);
  };

  return (
      <>
        <div className="App">
          <h1>Practice makes perfect</h1>
          {state?.isLoading ? (
              <p>Loading...</p>
          ) : (
              <button onClick={() => handleClick()}>
                {state?.isLogin ? "Logout" : "Login"}
              </button>
          )}
          <p>{state?.isLogin ? `Hello ${state?.user}` : "Please Login"}</p>
        </div>
      </>
  );
};

export default App;

Upvotes: 1

Chris Farmer
Chris Farmer

Reputation: 25415

You could do it like this... your example is simple enough that you can do it this way and maybe you wouldn't want to do this in a "real" app, but first calling setState with your loading state, followed by an async call (here using setTimeout) to get your logged-in user info should work ok:

  const handleClick = () => {
    // Loading here while we wait for the setTimeout to kick off.
    setState({
      isLoading: true,
      user: undefined,
      status: "Loading",
      isLogin: false
    });

    setTimeout(() => {
      // Assume success here
      setState({
        isLoading: false,
        user: "Logged-in Username",
        status: "success",
        isLogin: true
      });
    }, 2000);
  };

Here's a codesandbox where this is running. https://codesandbox.io/s/ecstatic-poincare-2jpio?file=/src/App.js

Upvotes: 1

Related Questions