使用useState挂钩的react组件是否会重新渲染每个setState调用?

时间:2019-03-16 00:01:51

标签: javascript reactjs react-hooks

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中的Promise被拒绝,我希望组件在挂载时呈现,然后在捕获到错误时第二次呈现。因此,我希望共有2个具有以下状态的渲染器:

第一个渲染:

  • isLoading:是
  • hasError:false

第二个渲染:

  • isLoading:否
  • hasError:正确

相反,该组件似乎在setLoading(false)之后重新呈现,而在setError(true)之后再次呈现。所以,我明白了:

第一个渲染:

  • isLoading:是
  • hasError:false

第二个渲染:(为什么?)

  • isLoading:否
  • hasError:false

第三次渲染:

  • isLoading:否
  • hasError:正确

我怀疑问题出在某种程度上是我在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 个答案:

答案 0 :(得分:2)

看起来这与状态更新的批处理有关。据我所知,基于React的事件将触发批处理更新,但不会触发在其外部触发的更新。 promise

由于状态调用未批处理,因此您看到2nd render都设置为false