Formik: загрузка файла как formData не работает с Redux - PullRequest
0 голосов
/ 16 мая 2019

Я пытаюсь сделать простую загрузку файлов с помощью redux-saga и formik, которая заботится о моих формах.

Сервер продолжает возвращать 400 error (неверный ввод), моему серверу нужен объект formData со свойством file.

Это моя форма с использованием Formik:

  <Formik
    initialValues={{ file: null }}
    validationSchema={CreateWorkspaceSchema}
    onSubmit={(values: FormikValues, { resetForm }: FormikActions<FormikValues>) => {
      resetForm({})
      onSubmit(values)
    }}
  >
    {({
      values,
      errors,
      touched,
      handleChange,
      handleSubmit,
      setFieldValue
    }) =>
      <Modal
        title="Create a workspace"
        visible={showModal}
        onOk={handleSubmit}
        okButtonProps={{ htmlType: "submit" }}
        onCancel={onShowModal}
        okText='Create'
      >
        <Spin spinning={status === ProgressStatus.InProgress}>
          {message ? <Alert type="error" closable message={message} showIcon style={{ marginBottom: "10px" }} /> : null}
          <Form onSubmit={handleSubmit}>
            <Upload beforeUpload={() => false} multiple={false} name="file" listType="picture" onChange={(event) => {
               setFieldValue("file", event.fileList[0]);
              }}>
              <Button>
                <Icon type="upload" /> Upload image
              </Button>
            </Upload>
          </Form>
        </Spin>
      </Modal>
    }
  </Formik>

Я использую пользовательский компонент Upload из Ant Design onChange запускается при загрузке нового файла и правильно добавляется в formikValues

My onSubmit заботится о запуске моего redux-saga действия:

onCreateWorkspace = (values: FormikValues) => {
    const { user, createWorkspace } = this.props;
    createWorkspace(Object.assign(
        values,
        {
            owner: `api/users/${user.id}`
        }
    ) as CreateWorkspaceValues)
}

Моя сага:

const formData = new FormData();
formData.append('file', action.payload.file)

const fileResponse = yield call(
  fetch,
  `${api.url}/api/media_objects`,
  {
    method: 'POST',
    body: formData
  }
);
return console.log(fileResponse);

Я пыталсядобавив следующий заголовок:

headers: { 'content-type': 'multipart/form-data' }

Но ошибка остается прежней.

Я попытался сделать то же самое в Postman, чтобы увидеть, было ли что-то не так с моим внутренним сервером, но загрузка файлав почтальоне работает как положено.Моя загрузка в почтальоне выглядит следующим образом:

enter image description here

Что мне здесь не хватает?

1 Ответ

0 голосов
/ 20 мая 2019

Я уже рассматривал ту же проблему некоторое время назад, и кажется, что решение «простое», но сложное для понимания, поскольку поток реквизита не был очень очевидным (по крайней мере, для меня). Я постараюсь описать схему того, как мне удалось загрузить файл с redux-saga, как можно проще:

Во-первых, чтобы соединить наш Formik компонент с redux, нам нужно обернуть его HOC. Это можно сделать с помощью withFormik() API следующим образом:

import { connect } from 'react-redux';
import { withFormik } from 'formik';
import Demo from './Demo'; // <--- the form component to be upgraded using this HOC
import * as types from './types';

const Form = withFormik({
    handleSubmit: (values, { props }) => {
        props.uploadFile(values); // <<--- Some action passed down from redux connect
    }
})(Demo);

const mapStateToProps = state => ({
    uploading: state.uploading
});

const mapDispatchToProps = dispatch => ({
    uploadFile: (
        values // <<-- Here's where the action is passed down
    ) =>
        dispatch({
            type: types.UPLOAD_FILE_REQUEST,
            payload: values
        })
});

export default connect(
    mapStateToProps,
    mapDispatchToProps
)(Form);

Во-вторых, теперь, когда мы обновили наш Formik компонент, мы можем dispatch действия и использовать в нем наш магазин.

Наконец, чтобы загрузить файл, мы можем использовать redux-saga следующим образом:

import { put, takeLatest } from 'redux-saga/effects';
import * as types from './types';
import reqwest from 'reqwest';
import { message } from 'antd';

function* uploadFileSaga({ formData }) {
    try {
        // You can use any AJAX library you like
        const request = yield reqwest({
            url: 'https://www.mocky.io/v2/5cc8019d300000980a055e76',
            method: 'post',
            processData: false,
            data: formData,
            success: () => {
                message.success('upload successfully.');
            },
            error: () => {
                message.error('upload failed.');
            }
        });
        if (request.status === 'done') {
            yield put({ type: types.UPLOAD_FILE_SUCCESS });
        }
    } catch (e) {
        console.log(e);
    }
}

export default function* rootSaga() {
    yield takeLatest(types.UPLOAD_FILE_REQUEST, uploadFileSaga);
}

Эта сага использует reqwest для обработки вызовов AJAX (так же, как в Ant-Design). Хотя вы можете выбрать любую библиотеку, с которой хотите работать.

Вы можете зайти в эту песочницу и посмотреть полную демонстрацию и узнать, как она работает вместе с Ant-Design.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...