繁体   English   中英

在 React useEffect 钩子中设置状态

[英]Setting state in React useEffect hook

在我的应用程序中,单击更改endpoint状态的按钮后,我从我的 API 获取数据。 在获取数据之前,我想显示一个加载图标。 经过大量测试,我终于让它工作了。 这是它的样子:

  const [endpoint, setEndpoint] = useState('products');
  const [loading, setLoading] = useState(true);
  const [data, setData] = useState([]);

  useEffect(() => {
    setLoading(true);

    fetch(`/api/${endpoint}`, {
      method: 'GET',
    })
    .then(res => res.json())
    .then(data => {
      setData(data);
    })
    .catch(e => {
      setData([]);
    })
    .finally(() => setLoading(false));

  }, [endpoint]);

  const onSelect = (option) => {
    setEndpoint(option);
  }

  return (
    <>
      <Sidebar onSelect={onSelect}/>
      <div className="main">
        <Banner />
        {loading ? 'Loading...' : JSON.stringify(data)}
      </div>
    </>
  );

尽管我得到了我想要的结果,但我对它们如何组合在一起有点困惑,因为我是 React 新手。 如果我错了,请纠正我,但这是我的理解:

setEndpoint触发重新渲染,这会导致useEffect执行,因为它依赖于endpoint useEffect中的每个设置状态调用也会导致重新渲染。 例如,当setLoading(true)时,屏幕会重新渲染以显示“正在加载...”。 一旦loading状态设置为true ,就会调用fetch 一旦 promise 被解决, setData(data)就会导致另一个重新渲染。 但是,在调用setLoading(false)之前,我的数据不会显示在屏幕上,再次重新渲染屏幕,显示我的数据。 所以总的来说,屏幕被重新渲染了 3 次(对吧?)。

我仍然感到困惑,因为我的印象是useEffect之类的钩子是异步的,那么为什么它要等待状态设置后再继续执行下一行代码呢?

useEffect挂钩回调是完全同步的。 你看到的是异步 Promise 链在工作。

useEffect(() => {
  setLoading(true); // (3)

  fetch(`/api/${endpoint}`, { // (4)
    method: 'GET',
  })
    .then(res => res.json())
    .then(data => {
      setData(data); // (6)
    })
    .catch(e => {
      setData([]); // (6)
    })
    .finally(() => setLoading(false)); // (7)
}, [endpoint]); // (2)

const onSelect = (option) => {
  setEndpoint(option); // (1)
}

...

{loading ? 'Loading...' : JSON.stringify(data)} // (5), (8)

您解释为您的理解的内容在很大程度上是正确的。

  1. endpoint状态更新入队,回调函数完成并处理状态更新,触发重新渲染。
  2. 调用useEffect挂钩,检查其依赖关系。 由于endpoint值更新, useEffect回调被调用。
  3. loading状态更新入队 回调函数仍在运行。
  4. 发出fetch请求。 fetch返回一个 Promise,代码启动一个 Promise 链。 这个链是异步的。 useEffect挂钩回调现在完成,因为没有更多同步代码要运行。 处理loading状态更新并触发重新渲染。
  5. UI 有条件地呈现加载指示器。
  6. 在这里,Promise 链要么已解决,要么已被拒绝, data状态更新队并在链中返回 Promise。 处理data状态更新并触发重新渲染。
  7. Promise 链的末端, loading状态更新入队 处理loading状态并触发重新渲染。
  8. UI 现在有条件地呈现数据。

所以总的来说,屏幕被重新渲染了 3 次(对吧?)。

根据我的统计,上面的逻辑可能触发了 4 次重新渲染,但 React 可能会因为任何其他原因重新渲染任意次数。 当 state 或 props 更新,或者父组件重新渲染时,React 组件会重新渲染。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM