等待直到flag = true失败,flag始终为false

时间:2019-10-07 00:15:29

标签: typescript react-hooks

我正在尝试创建一个自定义钩子,以将数据保存在服务器上。现在,我正在用一个简单的setTimeout伪造服务器调用,该命令会在2秒后在true上设置数据创建标志。

我有一个函数可以在解决Promise之前不断检查该标志。

但是,该标志永远不会为真。这是codesandbox

我看过其他有关此事的帖子,但是我无法实现该解决方案。

app.tsx

function App() {
  const { createOrganization } = useCreateOrganization();
  const handleCreateOrg = () => {
    createOrganization("New Org Name");
  };

  return (
    <div className="App">
      <button onClick={handleCreateOrg}>Start process</button>
    </div>
  );
}

useCreateOrganization.tsx

export const useCreateOrganization = (): {
  createOrganization: (organizationName: string) => Promise<any>;
} => {
  const [isOrganizationCreated, setIsOrganizationCreated] = useState(false);

  useEffect(() => {
    if (isOrganizationCreated) {
      setIsOrganizationCreated(true);
    }
  }, [isOrganizationCreated]);

  // Fakes org creation on a server.
  const mockCreateOrg = (orgName: string) => {
    setTimeout(() => {
      setIsOrganizationCreated(true);
    }, 1500);
  };

  function until(conditionFunction): Promise<any> {
    const poll = (resolve, reject) => {
      if (conditionFunction()) {
        console.log("done");
        resolve();
      } else {
        console.log("not done yet!");
        setTimeout(_ => poll(resolve, reject), 500);
      }
    };

    return new Promise(poll);
  }

  const createOrganization = async (organizationName: string): Promise<any> => {
    mockCreateOrg(organizationName);
    setIsOrganizationCreated(false);
    return await until(() => isOrganizationCreated);
  };

  return { createOrganization };
}

1 个答案:

答案 0 :(得分:1)

isOrganizationCreated将始终保留初始值false,因为在useCreateOrganization的函数范围内永远不会为变量分配新值-因此它更像是一种基本的JavaScript结束符(如果您想了解更多,请看下方的* 1)

问题还在于,您想在React world中实现命令式样式轮询(until)。相反,您应该通过使用stateprops来触发React的声明性,以触发新的渲染周期。因此,您可以调用mockCreateOrg API而不是轮询,而API依次设置新状态。这种新状态会触发重新呈现,这可能会导致副作用-例如console.log("done")

我不确定,为什么要在示例中准确使用Hooks,所以这是一个具有三种状态的基本提取示例:1)Hook位于"idle"中; 2)组织正在创建("pending"),3)orga创建已完成("created")。

Codesandbox

import * as React from "react";
import { render } from "react-dom";
import { useEffect, useState } from "react";

export const useCreateOrganization = (): {
  createOrganization: (organizationName: string) => Promise<any>;
} => {
  const [state, setState] = useState<"idle" | "pending" | "created">("idle");

  useEffect(() => {
    let interval;
    if (state === "pending") {
      interval = setInterval(() => console.log("not done yet!"), 500);
    } else if (state === "created") {
      console.log("done");
      // ...do some other things here...
      setState("idle");
    }
    return () => interval && clearInterval(interval);
  }, [state]);

  // Fakes org creation on a server.
  const mockCreateOrg = (orgName: string) => {
    setTimeout(() => {
      setState("created");
    }, 1500);
  };

  const createOrganization = async (organizationName: string): Promise<any> => {
    mockCreateOrg(organizationName);
    setState("pending");
  };

  return { createOrganization };
};

function App() {
  const { createOrganization } = useCreateOrganization();
  const handleCreateOrg = () => {
    createOrganization("New Org Name");
  };

  return (
    <div className="App">
      <button onClick={handleCreateOrg}>Start process</button>
    </div>
  );
}

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

更多信息:React Hooks中的闭包(* 1)

调用闭包createOrganization时,它将使用在外部作用域(isOrganizationCreated函数体)中定义的变量useCreateOrganization,在调用时其初始状态值为{{ 1}}。在此范围内,false的字面值将始终为isOrganizationCreated,永远不会发生重新分配(也无法使用false)。通过使用const触发状态更改,React在内部更新其component memory cell,并使用新的渲染周期再次调用setIsOrganizationCreated-现在具有更新的useCreateOrganization状态。但这并不会改变第一个isOrganizationCreated调用的关闭范围。

希望,它会有所帮助。