Реагирует ли компонент, использующий ловушку useState, на каждый вызов `setState`? - PullRequest
0 голосов
/ 16 марта 2019

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
});

1 Ответ

2 голосов
/ 16 марта 2019

Похоже, это как-то связано с пакетным обновлением состояния.Насколько я знаю, события на основе React будут запускать пакетные обновления, но не то, что запускается вне его.promise в этом случае.

Поскольку вызовы состояния не являются пакетными, вы видите 2nd render, где оба установлены на false

...