Consider this little react app:
import React, { Component } from "react";
import PropTypes from "prop-types";
import { Audio } from "react-loader-spinner";
import "./styles.css";
async function blockingUI() {
let x = 0;
for (let i = 0; i < 10000; i++) {
for (let j = 0; j < 10000; j++) {
x = Math.sqrt(x + i * j);
}
}
return x;
}
async function setTimeoutAsync(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
class Foo extends Component {
static propTypes = {
classes: PropTypes.object,
style: PropTypes.object,
};
static defaultProps = {};
// -------- Public: Reactjs --------
constructor(props) {
super(props);
this.state = {
...props,
isLoading: false,
};
}
setLoading = (isLoading) => {
this.setState({
isLoading: isLoading,
});
};
setLoadingAsync(isLoading) {
return new Promise((resolve) => {
this.setState({
isLoading: isLoading
}, resolve)
});
}
onBlockingUi = async () => {
let widget = this;
widget.setLoading(true);
console.time("blockingUI");
await blockingUI();
console.timeEnd("blockingUI");
widget.setLoading(false);
};
onBlockingUiHacked = async () => {
let widget = this;
widget.setLoading(true);
await setTimeoutAsync(20);
console.time("blockingUI");
await blockingUI();
console.timeEnd("blockingUI");
widget.setLoading(false);
};
onNonBlockingUi = async () => {
let widget = this;
widget.setLoading(true);
await setTimeoutAsync(1000);
widget.setLoading(false);
};
render() {
const loader = this.state.isLoading ? (
<Audio heigth="100" width="100" color="grey" ariaLabel="loading" />
) : null;
return (
<div className="App">
<h1>Loading test</h1>
<h2>Click to see some magic happen!</h2>
<button onClick={this.onBlockingUi}>Blocking UI</button>
<br/>
<button onClick={this.onBlockingUiHacked}>Blocking UI + hack</button>
<br/>
<button onClick={this.onNonBlockingUi}>Non-blocking UI</button>
{loader}
</div>
);
}
}
export default function App() {
return <Foo />;
}
In the above example there are 3 buttons:
- When I press the one that says “Blocking UI” the spinner widget won’t show up and the UI will freeze up.
- When I press the one that says “Blocking UI + hack” the spinner widget will show up but it won’t update/re-render properly (UI frozen up)
- When I press the one that says “Non blocking UI”, everything works ok.
I’d like to know what’d be the best practice here so I can avoid blocking the UI when trying to run these type of CPU intensive functions such as blockingUI
while displaying some loading html elements.
You can find the codesanbox here: https://codesandbox.io/s/sharp-roman-bouy9l