Home > Software engineering >  React: button with spinner, how to know when the animation should stop?
React: button with spinner, how to know when the animation should stop?

Time:03-08

I would like to create a custom button component that shows a loading spinner within itself when it's pressed and with a condition that can be externally defined which will tell the button to remove the spinner and return to its original appearance. Something like this:

<CustomButton
  type="button"
  className="btn btn-primary"
  stopSpinningWhen={condition}
  onClick={() => ...}
>
  Click me
</CustomButton>

Currently, my buttons with a spinner look like this, which is super fine, but it's a pain to write repetitive code/states for each single button:

const [buttonSpinner, setButtonSpinner] = useState(false);

const onClickEvent = (ev) => {
  setButtonSpinner(true);

  if (condition) {
    setButtonSpinner(false);
  }
};

return (
  <button
    type="button"
    className="btn btn-primary"
    onClick={onClickEvent}
    disabled={buttonSpinner}
  >
    {buttonSpinner ? (
      <span
        className="spinner-border spinner-border-sm"
        role="status"
        aria-hidden="true"
      ></span>
    ) : (
      "Click me"
    )}
  </button>
);

I'm using React 17.0.2.

Is it even possible?

CodePudding user response:

You can create your own custom button that receives isLoading additionally.

const Spinner = (
  <span
    className="spinner-border spinner-border-sm"
    role="status"
    aria-hidden="true"
  />
)

const CustomButton = (props) => (
  <button
    type="button"
    className="btn btn-primary"
    onClick={props.onClick}
    disabled={props.isLoading}
  >
    {props.isLoading ? <Spinner /> : "Click me"}
  </button>
)

const YourComponent = () => {
  const [isLoading, setIsLoading] = useState(false)
  const onClick = async(event) => {
    setIsLoading(true)
    doHeavyTask()
    setIsLoading(false)
  }
  return (
    <div>
      <CustomButton isLoading={isLoading} onClick={onClick} />
    </div>

  )
}

CodePudding user response:

You use a loading property as your condition and just pass that as a prop to your custom button component. Something like this:

const myComponent = () =>{

const [loading, setLoading] = useState(false)

const myFunc = async () = {
 setLoading(true)
 //call api or do seomthing, after the process finishes set loading to false again
 const resp = await fetch("myAPIURL")
 console.log(resp.data)
 setLoading(false)
}

return(

<CustomButton
  type="button"
  className="btn btn-primary"
  spinning={loading}
  onClick={() => myFunc()}
>
  Click me
</CustomButton>
)

}
  • Related