score:1

Accepted answer

Instead of passing inProgress prop to TestComponent, you could maintain a local state in the TestComponent that is used to determine whether to show progress text or a button and only pass the id and onClickHanlder props to TestComponent.

When button is clicked in TestComponent, you could set the the local state of TestComponent to show the progress text and then call the onClickHandler function passed as prop, passing in the id prop and a callback function as arguments. This callback function will be called when API request is completed. This callback function is defined inside TestComponent and only toggles the local state of the TestComponent to hide the progress text and show the button again.

Change your TestComponent to as shown below:

const TestComponent = ({ id, onClickHandler }) => {
  const [showProgress, setShowProgress] = React.useState(false);

  const toggleShowProgress = () => {
    setShowProgress(showProgress => !showProgress);
  };

  const handleClick = () => {
    setShowProgress(true);
    onClickHandler(id, toggleShowProgress);
  };

  return (
    <div>
      {showProgress ? (
        <p>In Progress </p>
      ) : (
        <button onClick={handleClick}>click me</button>
      )}
    </div>
  );
};

i have used useState hook to maintain local state of the TestComponent as it is a functional component but you could use the same logic in a class component as well.

Change the TestComponent in sampleData array to only be passed two props, id and onClickHandler.

{
   id: 1,
   name: "Product one",
   action: <TestComponent id={1} onClickHandler={this.onClickHandler} />
 }

and change onClickHandler method in App component to:

onClickHandler(id, callback) {
   // make the api request, call 'callback' function when request is completed
    setTimeout(() => {
      callback();
    }, 3000);
}

Demo

Edit crazy-fire-fvlhm

Alternatively, you could make onClickHandler function in App component to return a Promise that is fulfilled when API request completes. This way you don't have to pass a callback function from TestComponent to onClickHandler method in App component.

Change onClickHandler method to:

onClickHandler(id) {
   return new Promise((resolve, reject) => {
     setTimeout(resolve, 3000);
   });
}

and change TestComponent to:

const TestComponent = ({ id, onClickHandler }) => {
  const [showProgress, setShowProgress] = useState(false);

  const toggleShowProgress = () => {
    setShowProgress(showProgress => !showProgress);
  };

  const handleClick = () => {
    setShowProgress(true);

    onClickHandler(id)
      .then(toggleShowProgress)
      .catch(error => {
        toggleShowProgress();
        // handle the error
      });
  };

  return (
    <div>
      {showProgress ? (
        <p>In Progress </p>
      ) : (
        <button onClick={handleClick}>click me</button>
      )}
    </div>
  );
};

Demo

Edit practical-sinoussi-r92qj


Related Query

More Query from same tag