https://codesandbox.io/s/mow5zl5729
import React, { useEffect } from "react";
import ReactDOM from "react-dom";
import axios from "axios";
function useLoading() {
const [isLoading, setLoading] = React.useState(true);
const [hasError, setError] = React.useState(false);
const loadStuff = aPromise => {
return aPromise
.then(() => {
setLoading(false);
})
.catch(() => {
setLoading(false);
setError(true);
});
};
return { isLoading, hasError, loadStuff };
}
function App() {
const { isLoading, hasError, loadStuff } = useLoading();
useEffect(() => {
loadStuff(axios.get(`https://google.com`));
}, []);
console.log(isLoading, hasError);
return <div />;
}
Это упрощенный пример того, что я имею в виду.
Если обещание внутри useLoading
отклонено, я ожидал, что компонент будет отображаться при монтировании, а затем визуализироваться второй раз, когда ошибка обнаружена. Итак, я ожидаю всего 2 рендеров со следующим состоянием:
1й рендер:
- isLoading: true
- hasError: false
2-й рендер:
- isLoading: false
- hasError: true
Вместо этого кажется, что компонент перезапускается один раз после setLoading(false)
и снова после setError(true)
. Итак, я получаю это:
1й рендер:
- isLoading: true
- hasError: false
2-й рендер: (почему?)
- isLoading: false
- hasError: false
3-й рендер:
- isLoading: false
- hasError: true
Я подозреваю, что проблема в том, как я использую обещание внутри useEffect
, но я не уверен, где моя ментальная модель пошла не так.
РЕДАКТИРОВАТЬ:
Когда я изменяю useLoading
на 1 useState
, проблема исчезает.
сломано:
const [isLoading, setLoading] = React.useState(true);
const [hasError, setError] = React.useState(false);
работ:
const [loadingState, setLoadingState] = React.useState({
loading: true,
error: false
});