处理上传到 Cloudinary 的空图像字段

Handle empty image field upload to Cloudinary

在这个项目中,我有一个带有 input type='file' 的 Redux 表单,用于将图像上传到 Cloudinary 以及将其他数据上传到 MongoLab。该表单与项目 (Book) 创建组件 (booklist\client\src\components\AddBook.js) 和用于编辑 Book (booklist\client\src\components\Book.js).[=30= 的组件重用]

AddBookForm 形式。 book 属性来自父 Book 组件。其他Field被省略了。

class AddBookForm extends Component {
  componentDidMount() {
    this.handleInitialize();
  }

  handleInitialize() {
    let names = '';

    if (this.props.book) {
      const authors = this.props.book.authors && this.props.book.authors.map(ath => {
        let str = `${ath.firstname} ${ath.lastname}, `;
        names = names + str;
      });
      names = names.slice(0, -2);
    }

    const initData = {
      'title': this.props.book && this.props.book.title || '',
      'pages': this.props.book && this.props.book.pages || 0,
      'publisher': this.props.book && this.props.book.publisher || '',
      'publishedAt': this.props.book && moment(this.props.book.publishedAt).format('MM.DD.YYYY') || '',
      'releasedAt': this.props.book && moment(this.props.book.releasedAt).format('MM.DD.YYYY') || '',
      'isbn13': this.props.book && this.props.book.isbn13 || '',
      'cover': this.props.book && this.props.book.cover || '',
      'authors': names,
      book_id: this.props.book && this.props.book._id,
      cloudinarySecureUrl: this.props.book && this.props.book.cloudinarySecureUrl
    };

    this.props.initialize(initData);
  }

  render() {
    const { onSubmit, handleSubmit, pristine, reset, submitting } = this.props;

    return (
      <form onSubmit={handleSubmit(onSubmit)}>
        <Field
          name='cover'
          type='file'
          component={fileField}
          label='Cover'
          comment='Please provide a cover. Optional'
        />
        <button
          disabled={submitting}
          className='add-form-action'
        >
          Add Book
        </button>
        <button type='button' disabled={pristine || submitting} onClick={reset}>
          Clear Values
        </button>
      </form>
    )
}

export default AddBookForm = reduxForm({
  form: 'AddBookForm'
})(AddBookForm);

处理表单提交的Book组件方法

onSubmit(formData) {
    const authors = formData.authors;
    const authorsToArray = [];
    const authorsArray = authors.split(',');

    for (let ath of authorsArray) {
      const firstname = ath.trim().split(' ')[0];
      const lastname = ath.trim().split(' ')[1] || '';

      authorsToArray.push({
        firstname,
        lastname
      });
    }

    formData.authors = authorsToArray;

    this.props.addBook(formData, this.props.history);
  }

这是处理 Book 表单数据上传的 addBook() 操作。

export const addBook = (bookData, history) => (dispatch) => {
    const cloudinaryUrl = 'https://api.cloudinary.com/v1_1/*******/upload';
    const cloudinaryUploadPreset = '*******';

    const formData = new FormData();
    formData.append('file', bookData.cover[0]);
    formData.append('upload_preset', cloudinaryUploadPreset);

    axios({
        url: cloudinaryUrl,
        method: 'POST',
        headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
        data: formData
    })
        .then(res => {
            bookData.cloudinarySecureUrl = res.data.secure_url;

            axios.post('/api/books', bookData)
                .then(res => {
                    history.push('/')
                })
                .catch(err => dispatch({
                    type: GET_ERRORS,
                    payload: err.response.data
                }));
        })
        .catch(error => console.log('Cloudinary image upload error:', error.message));
};

我默认 bookData.cover[0] 是什么,这样我就可以为 Field name='cover' 提交没有图像的表单?难道there/should我走别的路?完整的回购在 https://github.com/ElAnonimo/booklist

更新

addBook() 操作的 catch 子句中添加了编辑 Book 时不上传图像的操作,我得到了正确的图书列表,即使图像仍然存在图片上传时。

.catch(error => {
  history.push('/');
});

这就是我在书创作行动中所做的。

// add book
export const addBook = (bookData, history) => (dispatch) => {
    const cloudinaryUrl = 'https://api.cloudinary.com/v1_1/dlzbcvsbf/upload';
    const cloudinaryUploadPreset = 'hvqidzpj';

    const formData = new FormData();

    // bookData.cover is the `FileList` array created when user submits a cover picture, bookData.cover[0] is the actual cover picture file
    bookData.cover && bookData.cover[0] && formData.append('file', bookData.cover[0]);

    formData.append('upload_preset', cloudinaryUploadPreset);

    if (!bookData.cover[0]) {
        axios.post('/api/books', bookData)
            .then(res => {
                history.push('/')
            })
            .catch(err => dispatch({
                type: GET_ERRORS,
                payload: err.response.data
            }));
    } else {
        axios({
            url: cloudinaryUrl,
            method: 'POST',
            headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
            data: formData
        })
            .then(res => {
                // book cover isn't stored in the DB no need to send it to backend
                delete bookData.cover;
                bookData.cloudinarySecureUrl = res.data.secure_url;

                axios.post('/api/books', bookData)
                    .then(res => {
                      history.push('/')
                    })
                    .catch(err => dispatch({
                        type: GET_ERRORS,
                        payload: err.response.data
                    }));
            })
            .catch(error => {
                console.log('Cloudinary image upload error:', error.message);
                history.push('/');
            });
    }
};