当前位置: 首页 > 面试题库 >

使用react-hooks在状态更新时执行异步代码

墨阳羽
2023-03-14
问题内容

我有类似的东西:

const [loading, setLoading] = useState(false);

...

setLoading(true);
doSomething(); // <--- when here, loading is still false.

设置状态仍然是异步的,那么等待此setLoading()调用完成的最佳方法是什么?

setLoading()似乎并没有接受一个回调像setState()使用。

一个例子

基于类

getNextPage = () => {
    // This will scroll back to the top, and also trigger the prefetch for the next page on the way up.
    goToTop();

    if (this.state.pagesSeen.includes(this.state.page + 1)) {
      return this.setState({
        page: this.state.page + 1,
      });
    }

    if (this.state.prefetchedOrders) {
      const allOrders = this.state.orders.concat(this.state.prefetchedOrders);
      return this.setState({
        orders: allOrders,
        page: this.state.page + 1,
        pagesSeen: [...this.state.pagesSeen, this.state.page + 1],
        prefetchedOrders: null,
      });
    }

    this.setState(
      {
        isLoading: true,
      },
      () => {
        getOrders({
          page: this.state.page + 1,
          query: this.state.query,
          held: this.state.holdMode,
          statuses: filterMap[this.state.filterBy],
        })
          .then((o) => {
            const { orders } = o.data;
            const allOrders = this.state.orders.concat(orders);
            this.setState({
              orders: allOrders,
              isLoading: false,
              page: this.state.page + 1,
              pagesSeen: [...this.state.pagesSeen, this.state.page + 1],
              // Just in case we're in the middle of a prefetch.
              prefetchedOrders: null,
            });
          })
          .catch(e => console.error(e.message));
      },
    );
  };

转换为基于功能的

  const getNextPage = () => {
    // This will scroll back to the top, and also trigger the prefetch for the next page on the way up.
    goToTop();

    if (pagesSeen.includes(page + 1)) {
      return setPage(page + 1);
    }

    if (prefetchedOrders) {
      const allOrders = orders.concat(prefetchedOrders);
      setOrders(allOrders);
      setPage(page + 1);
      setPagesSeen([...pagesSeen, page + 1]);
      setPrefetchedOrders(null);
      return;
    }

    setIsLoading(true);

    getOrders({
      page: page + 1,
      query: localQuery,
      held: localHoldMode,
      statuses: filterMap[filterBy],
    })
      .then((o) => {
        const { orders: fetchedOrders } = o.data;
        const allOrders = orders.concat(fetchedOrders);

        setOrders(allOrders);
        setPage(page + 1);
        setPagesSeen([...pagesSeen, page + 1]);
        setPrefetchedOrders(null);
        setIsLoading(false);
      })
      .catch(e => console.error(e.message));
  };

在上面,我们要顺序运行每个setWhatever调用。这是否意味着我们需要设置许多不同的useEffect挂钩来复制此行为?


问题答案:

useState状态更新完成后,setter不会提供回调,就像React类组件中的setState一样。为了复制相同的行为,您可以componentDidUpdate通过useEffect使用Hooks
在React类组件中使用类似模式的生命周期方法

useEffect 钩子将第二个参数作为值的数组,在渲染周期完成后,React需要监视这些值以进行更改。

const [loading, setLoading] = useState(false);

...

useEffect(() => {
    doSomething(); // This is be executed when `loading` state changes
}, [loading])
setLoading(true);

编辑

不同于setStateuseState钩子的更新程序没有回调,但是您始终可以使用a useEffect复制上述行为。但是,您需要确定加载变化

代码的功能方法如下所示

function usePrevious(value) {
  const ref = useRef();
  useEffect(() => {
    ref.current = value;
  });
  return ref.current;
}
const prevLoading = usePrevious(isLoading);

useEffect(() => {
   if (!prevLoading && isLoading) {
       getOrders({
          page: page + 1,
          query: localQuery,
          held: localHoldMode,
          statuses: filterMap[filterBy],
      })
      .then((o) => {
        const { orders: fetchedOrders } = o.data;
        const allOrders = orders.concat(fetchedOrders);

        setOrders(allOrders);
        setPage(page + 1);
        setPagesSeen([...pagesSeen, page + 1]);
        setPrefetchedOrders(null);
        setIsLoading(false);
      })
      .catch(e => console.error(e.message));
   }
}, [isLoading, preFetchedOrders, orders, page, pagesSeen]);

const getNextPage = () => {
    // This will scroll back to the top, and also trigger the prefetch for the next page on the way up.
    goToTop();

    if (pagesSeen.includes(page + 1)) {
      return setPage(page + 1);
    }

    if (prefetchedOrders) {
      const allOrders = orders.concat(prefetchedOrders);
      setOrders(allOrders);
      setPage(page + 1);
      setPagesSeen([...pagesSeen, page + 1]);
      setPrefetchedOrders(null);
      return;
    }

    setIsLoading(true);
  };


 类似资料:
  • 我有点像: 设置状态仍然是异步,那么等待这个调用完成的最佳方法是什么? 似乎不像那样接受回调。 在上面,我们希望按顺序运行每个setwhater调用。这是否意味着我们需要设置许多不同的useEffect挂钩来复制这种行为?

  • 问题内容: 我正在尝试新的React Hooks,并有一个带有计数器的Clock组件,该计数器应该每秒增加一次。但是,该值不会增加到超过一。 问题答案: 原因是传递给的闭包中的回调仅访问第一个渲染器中的变量,而无法访问后续渲染器中的新值,因为第二次未调用。 回调中的值始终为0 。 就像您熟悉的状态挂钩一样,状态挂钩有两种形式:一种是处于更新状态的状态,另一种是将当前状态传入的回调形式。您应该使用第

  • 我正在试用新的反应挂钩,并有一个时钟组件,计数器应该每秒钟增加一次。但是,该值不增加超过1。

  • 问题内容: 我正在尝试使用React Hooks和表单更新UI。我设置了一个状态来监视表单上的值,当我单击“提交”时,我想将此值添加到数组(保持状态)并在UI上显示。我的问题是,当我提交值时,尽管它已添加到数组中(状态已更新),但UI仅在更改输入中的值时才更新。 我的组件如下: 您也可以在以下 网址看到此[不]工作: https //codesandbox.io/s/p3n327zn3q 是否有人

  • 我正在开发一个小待办事项应用程序,作为使用React的练习。我有一个这样的模拟服务: 在我的React应用程序中,我有一些包含TODO的状态: 是一个函数,我将它传递到我的组件中,当我想完成这样一个Todo时使用: 因此,每当用户单击复选框并使用调用时,就会从服务对象中删除它,并且状态应该更新,但最奇怪的事情发生了。 当调用时,todo将被正确删除,但当调用时,旧的todo仍然存在!如果我将内容写

  • 我对JS中使用Promissions或async/await的异步操作还不熟悉,我正试着对这个概念进行总结。我遇到的一个问题是,如何在多个数组上循环并对每个元素执行异步操作时保持状态。例如,我有以下代码: 虽然上面的代码符合我的目的,但我试图更好地理解基于promise的代码。我意识到循环必须是同步的,逻辑才能工作,但API调用本质上是异步的。我不是在尝试创建异步代码,而是在尝试处理异步代码。暂停