Реакция: обновление и последующий доступ к состоянию после сетевого запроса в перехвате useEffect. Состояние остается устаревшим - PullRequest
0 голосов
/ 09 июля 2020

Я пытаюсь обновить и указать hasError поле состояния внутри функции инициализации моего компонента, чтобы контролировать, происходит ли перенаправление после успешной инициализации или отображается ошибка.

Вот сокращенная версия проблемы:

const [hasError, setHasError] = useState(false);

useEffect(() => {
  initialize();
}, []);

async function initialize(){
  try {
    await networkRequest();
  } catch (err) {
    setHasError(true);
  }
  console.log(hasError);  // <- is still false
  if(!hasError){
    redirect()  // <- causes redirect even with error
  }
}

function networkRequest() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      reject();
    }, 1000);
  });
}

Функция инициализации должна вызываться только один раз при монтировании компонента, поэтому я передаю [] в useEffect. Передача [hasError] в useEffect также не имеет смысла, так как я не хочу, чтобы инициализация выполнялась каждый раз hasError обновления.

Я видел, как люди рекомендуют использовать useReducer, но это кажется хакерским, поскольку я Я уже использую Redux для этого компонента, и тогда мне нужно будет использовать 2 разных dispatch экземпляра.

Как обычно обрабатывается такой вариант использования?

1 Ответ

1 голос
/ 09 июля 2020

Вам нужно будет создать еще один useEffect хук, который "прослушивает" изменения в hasError. setHasError в данном случае является асинхронным, поэтому новое значение не будет доступно вам сразу.

Я не знаю, как выглядит остальная часть вашего компонента, но похоже, что у вас должно быть несколько своего рода состояние isLoading, которое будет использоваться для отображения сообщения loading, а затем, когда ваш запрос завершится и он не удастся, вы отобразите то, что вам нужно, или, если он будет успешным, вы redirect.

Вот пример:

function App() {
  const [isLoading, setIsLoading] = useState(true);
  const [hasError, setHasError] = useState(false);

  useEffect(() => {
    (async () => {
      try {
        await networkRequest();
        isLoading(false);
      } catch (error) {
        setHasError(error);
        isLoading(false);
      }
    })()
  }, [])

  useEffect(() => {
    if (!isLoading && !hasError) {
      redirect();
    }
  }, [isLoading, hasError]);

  if (isLoading) { return "Loading"; }
  
  // else, do whatever you need to do here
}
...