const rootElement = document.getElementById("root");
ReactDOM.render(
<App />,
rootElement
)
function square(n, timeout = 1000) {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(n * n), timeout);
});
}
function App() {
const [number, setNumber] = React.useState(0);
const [loading, result, error, reload] = useAsync(
() => square(number, 1000),
[number]
);
console.log(number, result);
return (
<div className="App">
<div>
Decrement{" "}
<button
disabled={loading}
type="button"
onClick={e => setNumber(number => setNumber(number - 1))}
>
-
</button>
</div>
<div>Number: {number}</div>
<div>Its square: {result} {loading && <span className="fa fa-spinner"></span>}</div>
<div>
Increment
<button
type="button"
disabled={loading}
onClick={e => setNumber(number => setNumber(number + 1))}
>
+
</button>
</div>
</div>
);
}
function useAsync(func, dependencyArray = []) {
const [state, setState] = React.useState({
loading: false,
result: null,
error: null,
mounted: true
});
const reload = () => {
function call() {
setState(state => ({
...state,
loading: true,
error: null,
result: null
}));
func()
.then(res=>{
if (!state.mounted) return;
setState(state => ({
...state,
result: res,
loading: false
}));
})
.catch(err=>{
setState(state => ({
...state,
loading: false,
result: null,
error
}));
})
}
call();
};
React.useEffect(() => {
reload();
return () =>
setState({
...state,
loading: false,
result: null,
error: null
});
}, dependencyArray);
React.useEffect(() => {
setState(state => ({ ...state, mounted: true }));
return () => setState(state => ({ ...state, mounted: false }));
}, []);
return [state.loading, state.result, state.error, reload, setState];
}
.App {
font-family: sans-serif;
text-align: center;
display: flex;
justify-content: flex-start;
align-items: flex-start;
flex-direction: column;
}
button {
width: 100px;
height: 40px;
border-radius: 4px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>
<link href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" integrity="sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN" crossorigin="anonymous">
Я использую настраиваемый перехватчик реакции для вызова API и установки состояния в моем компоненте реакции. hook принимает функцию, которая возвращает массив обещаний и зависимостей. Крюк возвращает [loading, result, error, reload, setState]
. Я надеюсь, что результат будет сброшен, как только изменится зависимость хука, но состояние остается устаревшим для одного рендера, который нарушает logi c в компоненте. Действия по воспроизведению. I. Предположим, что число 2, тогда его квадрат равен 4. II. Откройте консоль. III. с шагом 2, число станет 3, через одну секунду квадрат будет 9. IV. В консоли вы увидите что-то вроде: 2 4 , 3 4 , 3 null , 3 9 V. 3 4 здесь содержит ошибки.