我正在尝试创建一个自定义钩子,以将数据保存在服务器上。现在,我正在用一个简单的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 };
}
答案 0 :(得分:1)
isOrganizationCreated
将始终保留初始值false
,因为在useCreateOrganization
的函数范围内永远不会为变量分配新值-因此它更像是一种基本的JavaScript结束符(如果您想了解更多,请看下方的* 1)
问题还在于,您想在React world中实现命令式样式轮询(until
)。相反,您应该通过使用state
和props
来触发React的声明性,以触发新的渲染周期。因此,您可以调用mockCreateOrg
API而不是轮询,而API依次设置新状态。这种新状态会触发重新呈现,这可能会导致副作用-例如console.log("done")
。
我不确定,为什么要在示例中准确使用Hooks,所以这是一个具有三种状态的基本提取示例:1)Hook位于"idle"
中; 2)组织正在创建("pending"
),3)orga创建已完成("created"
)。
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);
调用闭包createOrganization
时,它将使用在外部作用域(isOrganizationCreated
函数体)中定义的变量useCreateOrganization
,在调用时其初始状态值为{{ 1}}。在此范围内,false
的字面值将始终为isOrganizationCreated
,永远不会发生重新分配(也无法使用false
)。通过使用const
触发状态更改,React在内部更新其component memory cell,并使用新的渲染周期再次调用setIsOrganizationCreated
-现在具有更新的useCreateOrganization
状态。但这并不会改变第一个isOrganizationCreated
调用的关闭范围。
希望,它会有所帮助。