Redux Thunk - Изменить состояние перед запросом REST - PullRequest
0 голосов
/ 30 сентября 2019

Я новичок в Redux Thunk, и у меня возникла проблема с обновлением контракта с помощью FileList (приложение к файлу), но если я использую JSON.stringify, файл будет иметь значение 0. Если я преобразую файл в Base64, эта проблема будет решена, но запрос PUT будет выполнен до того, как файл будет конвертирован.

Я много искал о Redux Thunk и думаю, что это может быть какая-то проблема с Dispatch, я пытался довольномного и не стал намного мудрее. Большинство вещей, которые я попробовал, вернули: «Действия должны быть простыми объектами. Используйте пользовательское промежуточное ПО для асинхронных действий».

Буду признателен за помощь или несколько предложений поиска.

пс. contract.answers [0] .answer [0] - это файл. Это требует некоторого рефакторинга, но сначала это должно сработать.

const toBase64 = (file) => new Promise((resolve, reject) => {
  const reader = new FileReader();
  reader.readAsDataURL(file);
  reader.onload = () => resolve(reader.result);
  reader.onerror = (error) => reject(error);
});

export function updateContract(contract) {
  const base64File = toBase64(contract.answers[0].answer[0]);
  base64File.then((value) => {
    contract.answers[0].answer[0] = value; //Set file as base64
  });
  return {
    type: SAVE,
    fetchConfig: {
      uri: contract._links.self,
      method: 'PUT',
      headers: {
        Accept: 'application/json',
        'Content-Type': 'application/json',
      },
      body: JSON.stringify(contract), // Does not handle files
      failureHandler(error) {
        const {
          details,
          status,
        } = error;

        // If the contract was invalid, throw form errors:
        if (status.code === 400 && details) {
          // Map the question ids to fields:
          throw new SubmissionError(Object.keys(details).reduce(
            (acc, questionId) => {
              acc[`question${questionId}`] = details[questionId];
              return acc;
            },
            {},
          ));
        }

        return {
          type: SAVE_FAILURE,
          error,
        };
      },
      successHandler(json) {
        return {
          type: SAVE_SUCCESS,
          data: json,
        };
      },
    },
  };
}

С уважением, Gust de Backer

1 Ответ

0 голосов
/ 30 сентября 2019

Это происходит потому, что toBase64 возвращает Promise и само по себе является асинхронным, поэтому в вашем случае необходим инкапсула внутри нового then.

export function updateContract(contract) {
  const base64File = toBase64(contract.answers[0].answer[0]);
  base64File.then((value) => {
    contract.answers[0].answer[0] = value; //Set file as base64
  });
  return (dispatch) => {
    base64File.then(() => dispatch({
      type: SAVE,
      fetchConfig: {
        uri: contract._links.self,
        method: 'PUT',
        headers: {
          Accept: 'application/json',
          'Content-Type': 'application/json',
        },
        body: JSON.stringify(contract), // Does not handle files
        failureHandler(error) {
          const {
            details,
            status,
          } = error;

          // If the contract was invalid, throw form errors:
          if (status.code === 400 && details) {
            // Map the question ids to fields:
            throw new SubmissionError(Object.keys(details).reduce(
              (acc, questionId) => {
                acc[`question${questionId}`] = details[questionId];
                return acc;
              }, {},
            ));
          }

          return {
            type: SAVE_FAILURE,
            error,
          };
        },
        successHandler(json) {
          return {
            type: SAVE_SUCCESS,
            data: json,
          };
        },
      },
    }))
  };
}

Да, в редуксе принимают функцию каквозвращаем, что функция получает отправку по параметрам, вы можете использовать ее для отправки запроса после того, как преобразование будет готово:)

...