我在打字稿中有一个React Hook样式组件。我正在使用Office uifabric作为ui框架。我想让以下模式以“最佳实践”的方式工作:
onClick
事件的组件(在我的情况下是CommandBar)创建一个不异步的虚拟获取方法会使我的示例代码按预期工作。但是,当我进行异步调用时,某些内容会丢失,并且无法获得MessageBar的重新渲染和可见性。 api调用已完成!
const UserProfile = () => {
const [apiStatusCode, setApiResponseCode] = useState(0);
const [showMessageBar, setShowMessageBar] = useState(false);
const startAsync = () => {
// With await here I get a compiler
// error. Without await, the api call is made but
// the messagebar is never rendered. If the call is not async, things
// work fine.
myAsyncMethod();
};
const toggleMessageBar = (): (() => void) => (): void => setShowMessageBar(!showMessageBar);
const myAsyncMethod = async () => {
try {
const responseData = (await get('some/data'))!.status;
setApiResponseCode(responseData);
toggleMessageBar();
} catch (error) {
console.error(error);
setApiResponseCode(-1);
toggleMessageBar();
}
};
const getItems = () => {
return [
{
key: 'button1',
name: 'Do something',
cacheKey: 'button1', //
onClick: () => startAsync()
}
];
};
return (
<Stack>
<Stack.Item>
<CommandBar
items={getItems()}
/>
</Stack.Item>
{showMessageBar &&
<MessageBar messageBarType={MessageBarType.success} onDismiss={toggleMessageBar()} dismissButtonAriaLabel="Close">
Successfully retrieved info with status code: {apiStatusCode}
</MessageBar>
}
// Other ui parts go here
</Stack>
)
};
export default UserProfile;
将异步方法分配给onClick事件会导致编译器错误:
Type 'Promise<void>' is not assignable to type 'void'. TS2322
不等待异步调用会导致响应在调用完成后不重新呈现。
答案 0 :(得分:0)
一种常见的模式,它可以在执行操作时更新回调中的状态,然后使用useEffect
响应新数据:
useEffect(()=>{
setShowMessageBar(!showMessageBar)
},[apiStatusCode, showMessageBar])
const myAsyncMethod = async () => {
try {
const responseData = (await get('some/data'))!.status;
setApiResponseCode(responseData);
// toggleMessageBar(); <-- delete me
} catch (error) {
console.error(error);
setApiResponseCode(-1);
// toggleMessageBar(); <-- delete me
}
};
答案 1 :(得分:0)
最终找到了答案,关键是使用反应useEffect
机制。这个答案使我找到了解决方案:
Executing async code on update of state with react-hooks
我的代码中的主要更改:
创建状态以跟踪执行情况
const [doAsyncCall, setDoAsyncCall] = useState(false);
在onClick事件中设置状态:
const getItems = () => {
return [
{
key: 'button1',
name: 'Do something',
cacheKey: 'button1', //
onClick: () => setDoAsyncCall(true)
}
];
};
在取决于状态的useEffect节中包装异步功能:
useEffect(() => {
async function myAsyncMethod () {
try {
const responseData = (await get('some/data'))!.status;
setApiResponseCode(responseData);
setShowMessageBar(true);
} catch (error) {
console.error(error);
setApiResponseCode(-1);
setShowMessageBar(true);
}
}
if (doAsyncCall) {
myAsyncMethod();
}
}, [doAsyncCall]);