I am trying to build a simple UI displaying the progress of an ethereum transaction to mint an NFT using ERC-20 token as payment. So a single mint involves these steps:
- Get Token metadata URI from backend server
- Get token spending approval on ERC-20 contract
- Mint the NFT
- Lock the NFT in a staking contract
On react side, I am maintaining the steps and status of each step on react side as:
The Data types
enum LoadingState {
DONE,
IN_PROGRESS,
PENDING,
FAILED,
}
type Step = {
title: string;
state: LoadingState;
error?: Error;
};
const _steps: Step[] = [
{
title: "Getting Token metadata URI from backend server",
state: LoadingState.PENDING,
},
{
title: "Getting token spending approval",
state: LoadingState.PENDING,
},
{
title: "Minting NFT",
state: LoadingState.PENDING,
},
{
title: "Stacking NFT",
state: LoadingState.PENDING,
},
];
Inside react component; I have some long code; but I will summarise the flow with some comments. At the moment I am calling a single stackAndMint(..) function that then calls a function for each individual step.
const MintComponent {
const [steps, setSteps] = useState<>(_steps);
const stackAndMint = async (..) {
// Update the step 0 state to IN_PROGRESS
setSteps((steps_) => {
steps_[0].state = LoadingState.IN_PROGRESS;
return steps_;
});
const metadata = await getMetaData(tokenID);
// Update step 0 state to DONE and step 1 state to IN_PROGRESS
setSteps((steps_) => {
steps_[0].state = LoadingState.DONE;
steps_[1].state = LoadingState.IN_PROGRESS;
return steps_;
});
// Getting Token Approval
await approveTokens(spender, amount);
// Update step 1 state to DONE and step 2 state to IN_PROGRESS
setSteps((steps_) => {
steps_[1].state = LoadingState.DONE;
steps_[2].state = LoadingState.IN_PROGRESS;
return steps_;
});
// MintToken
await mintToken(owner, tokenID, tokenURI);
// Update step 2 state to DONE and step 3 state to IN_PROGRESS
setSteps((steps_) => {
steps_[2].state = LoadingState.DONE;
steps_[3].state = LoadingState.IN_PROGRESS;
return steps_;
});
// Stake token
await stakeToken(tokenID);
// Update step 3 state to DONE
setSteps((steps_) => {
steps_[3].state = LoadingState.DONE;
return steps_;
});
}
}
Now I have a simple list in the UI as following:
<ul>
{steps.map((step) => (
<li>{getIcon(step.state)} - {step.title}</li>
));
}
</ul>
Now I want that as the code executes and state of each step changes, the icon beside each step's title should change as per the state. But; in my case, the icons remains unchanged and then as all the steps are completed; all the icons changes to completed state at once at the end.
As per my exploration the reason behind this is; the react batches the state update to minimize the re-rendring of the components UI.
So my query is; How can i achieve the the result so that the icon behind each step updates as the step state is updated.