如何使用React Hooks API管理异步功能

时间:2019-08-02 06:05:55

标签: javascript reactjs asynchronous react-hooks

我正在与React Hooks合作,我正在尝试更新状态,然后进行异步操作,然后根据状态进行操作。这不起作用,因为更新功能在异步功能内不可用。您如何使用react hooks解决此类任务?

Demo

我基本上试图更改函数的范围,但显然它是不可改变的,这意味着异步函数内部的引用指向旧状态。

import React from "react";
import ReactDOM from "react-dom";

import "./styles.css";

// Constants
function somethingAsync(time) {
  return new Promise(resolve => setTimeout(resolve, time));
}

function App() {
  const [loading, setLoading] = React.useState(false);

  const doSomethingAsync = async () => {
    setLoading(true);
    await somethingAsync(2000);
    if (loading) {
      setLoading(false);
    }
  };
  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <p>Current Status: {loading ? "Loading" : "Not Loading"}</p>
      <button onClick={doSomethingAsync}>Do Something Async</button>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

我希望每次异步功能完成时都将加载标志重置为false,这应该基于在执行异步功能时已更新的状态来完成。现在,由于异步作用域中的旧引用,它只能每秒钟运行一次。

2 个答案:

答案 0 :(得分:3)

只需删除setLoading(false)通话中的if。

如果不这样做,该功能将访问陈旧的loading状态。因为创建该函数时,loading为假。因此,在运行异步功能之后,在等待之后,您的功能将恢复,即使loadingtrue,它也将其视为false。但是您会知道它将是true,因为只需设置它,并且App就会在await语句中重新渲染。请参见以下行为:

CodeSandbox

enter image description here

import React from "react";
import ReactDOM from "react-dom";

import "./styles.css";

// Constants
function somethingAsync(time) {
  return new Promise(resolve => setTimeout(resolve, time));
}

function App() {
  const [loading, setLoading] = React.useState(false);
  console.log("App rendering...");

  const doSomethingAsync = async () => {
    setLoading(true);
    console.log("Before await...");
    await somethingAsync(2000);
    console.log("After await...");
    setLoading(false);
  };
  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <p>Current Status: {loading ? "Loading" : "Not Loading"}</p>
      <button onClick={doSomethingAsync}>Do Something Async</button>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

答案 1 :(得分:1)

您只需要在异步函数中删除if条件:

  const doSomethingAsync = async () => {
      setLoading(true);
      await somethingAsync(2000);
      setLoading(false);      
    };