@Mjogan

Как выполнить действие только после dispatch-а асинхронной функции?

Добрый день.
У меня есть следующая функция в компоненте:
function uploadFile(canvas, crop) {
    if (!crop || !canvas) {
      return;
    }
    canvas.toBlob(async (blob) => {
      const formData = new FormData();
      formData.append('file', blob);

      dispatch(updateAvatar({ file: formData, userId: user._id }));

      setIsOpen(false);
      setUpImg(null);
      setCompletedCrop(null);
    });
  }

где updateAvatar - это
export const updateAvatar = createAsyncThunk(
  'user/updateAvatar',
  async ({ file, userId }, thunkApi) => {
    try {
      const response = await UserService.updateAvatar(file, userId);
      return response.data;

    } catch (err) {
...
}


мне нужно сделать так, чтобы код, находящийся ниже dispatch, отрабатывал только после выполнения асинхронного кода action-а.
Если я просто напишу вместо строки dispatch(updateAvatar({ file: formData, userId: user._id })) в функции следующий код, то работать все будет, но я потеряю все преимущества redux-toolkit и компонент станет "грязным", мне этого бы не хотелось.
const response = await UserService.updateAvatar(formData);
dispatch(updateAvatar(response.data));


я попробовал следующее:
в компонент с функцией выше я передаю пропс:
action={async (formData) => {
  return dispatch(updateAvatar({ file: formData, userId: user._id }));
}}


а саму функцию изменяю так:
function uploadFile(canvas, crop) {
    if (!crop || !canvas) {
      return;
    }
    canvas.toBlob(async (blob) => {
      const formData = new FormData();
      formData.append('file', blob);

      const test = await action(formData);

      if (test.meta.requestStatus !== 'pending') {
        setIsOpen(false);
        setUpImg(null);
        setCompletedCrop(null);
      }
    });
  }

и все работает, но мне кажется, это какой-то бред. и что делать, если в другом случае я не смогу передать такой пропс... уже не решить так.
в общем, прошу пояснить, как мне поступить для решения проблемы.
Спасибо
  • Вопрос задан
  • 547 просмотров
Пригласить эксперта
Ответы на вопрос 2
@gsaw
Если этот dispatch из useReducer, то она только планирует какие то изменения в данных, которые будут применены только в следующем цикле отрисовки. Игра с async не поможет. Вам надо использовать useEffect, что бы если какая то переменная в стейте изменится, useEffect-ом выполнить очистку переменных.

К примеру

useEffect(() => { 
      setIsOpen(false);
      setUpImg(null);
      setCompletedCrop(null);
},[uploaded])
Ответ написан
Комментировать
sasha-hohloma
@sasha-hohloma
Fullstack Developer
При работе с React любое изменение в интерфейсе необходимо отражать в state. Если вам необходимо получить данные асинхронно, значит ваш компонент будет иметь минимум 3 состояния: данные при инициализации, ожидание загрузки, данные получены. Также, dispatch всегда синхронный, именно поэтому нам и нужны библиотеки вроде React Thunk, которые выполняют отложенное изменение стейта. Поэтому, писать асинхронные action без вызова dispatch неправильно
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы