Вызовите асинхронный метод в событии onClick Office Fabric CommandBar, используя перехватчики реагирования? - PullRequest
0 голосов
/ 02 июля 2019

У меня есть компонент стиля реакционного хука в машинописи.Я использую офисный uifabric в качестве интерфейса.Я хочу, чтобы следующий шаблон работал «наилучшим образом»:

  1. У меня есть компонент с событием onClick (в моем случае CommandBar )
  2. Пользователь нажимает на действие
  3. Я выполняю асинхронный вызов серверного API (асинхронная часть вызывает у меня проблемы, я думаю, и это, к сожалению, требование).
  4. После завершения асинхронного вызова или сбоя.Я хочу показать MessageBar с информацией.
  5. В целом, используя как можно меньше кода, реагирует на хуки , кажется, имеет возможность генерировать хороший код и код соответствия.вместе с 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 голосов
/ 02 июля 2019

В конце концов нашел ответ, ключом было использование механизма useEffect реакции. Этот ответ привел меня к решению:

Выполнение асинхронного кода при обновлении состояния с помощью перехватчиков реакции

Ключевые изменения в моем коде:

Создание состояния для отслеживания выполнения

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]);
0 голосов
/ 02 июля 2019

Обычный шаблон для такого рода вещей - обновлять ваше состояние в обратном вызове, как вы делаете, а затем отвечать на новые данные с помощью 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
    }
  };
...