使用react hooks在Office Fabric CommandBar onClick事件中调用异步方法吗?

时间:2019-07-02 09:06:16

标签: reactjs typescript office-ui-fabric

我在打字稿中有一个React Hook样式组件。我正在使用Office uifabric作为ui框架。我想让以下模式以“最佳实践”的方式工作:

  1. 我有一个带有onClick事件的组件(在我的情况下是CommandBar
  2. 用户点击操作
  3. 我对后端api进行了异步调用(异步部分是我在这里引起麻烦的原因,很遗憾,这是必需的)。
  4. 异步调用完成或失败时。我想向MessageBar显示信息。
  5. 总而言之,react hooks只需使用尽可能少的代码,就可以与TypeScript一起生成美观的代码。但是我对这两种东西都是新手,所以我可能会在这里四处走动...

创建一个不异步的虚拟获取方法会使我的示例代码按预期工作。但是,当我进行异步调用时,某些内容会丢失,并且无法获得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

不等待异步调用会导致响应在调用完成后不重新呈现。

2 个答案:

答案 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]);