我的应用后端使用sails.js
,并且有一个API api/question/new
用于创建新问题。此API支持使用skipper
模块here上传文件或图片,我已验证在REST客户端PostMan
中使用文件字段进行上传以及文本字段title
,content
和tags
。
现在,我正在尝试使我的基于react.js的组件(问题表单)同时发布文本和上传文件。我遇到了一个名为react-dropzone
here的好库,我正在尝试将其与我的表单集成。 react.js中的表单由saga函数处理,以便使用whatwg-fetch
library进行发布。
问题表单组件:
export const fields = ['title', 'content', 'tags', 'images'];
const validate = values => {
const errors = {};
if (!values.title) {
errors.title = 'Required';
}
if (!values.content) {
errors.content = 'Required';
} else if (values.content.length < 2) { // TODO: specify a constant for length of content
errors.content = 'Question is too short';
}
return errors;
}
class QuestionForm extends React.Component {
constructor(props, context) {
super(props, context);
this.dropFile = this.onDrop.bind(this);
}
onDrop(files) {
console.log('received files: ', files);
this.props.fields.images = [];
files.forEach((file) => {
this.props.fields.images.push(file);
});
}
render() {
const { fields: {title, content, tags, images}, resetForm, handleSubmit, submitting, pristine} = this.props;
return (
<div className={ styles.QuestionForm }>
<form onSubmit={handleSubmit}>
<Row>
<label>Title</label>
<div>
<input className="form-control" type="text" maxlength="100" placeholder="Title" {...title} name="title" />
</div>
{title.touched && title.error && <div>{title.error}</div>}
</Row>
<Row>
<label>Content</label>
<div>
<input className="form-control" type="text" maxlength="100" placeholder="Content" {...content} name="content" />
</div>
{content.touched && content.error && <div>{content.error}</div>}
</Row>
<Row>
<label>Tags</label>
<div>
<input className="form-control" type="text" maxlength="100" placeholder="Tags" {...tags} name="content" />
</div>
</Row>
<Row>
<Dropzone onDrop={this.dropFile}>
<div>Try dropping some files here, or click to select files to upload.</div>
</Dropzone>
</Row>
<Row>
<label></label>
<button className="btn btn-warning" type="button" disabled={pristine || submitting} onClick={resetForm}>Clear Values</button>
<button className="btn btn-primary" type="submit" disabled={pristine || submitting}>Submit</button>
</Row>
</form>
</div>
);
}
}
以下是使用whatwg-fetch发布表单数据的传奇功能:
export function* askQuestion() {
while(true) {
const action = yield take(types.SUBMIT_QUESTION);
let askQUrl = 'http://localhost:1337/api/question/new';
const curToken = getJwtToken();
var formData = new FormData();
action.questionObj.images.forEach(function(img) {
formData.append('images', img);
});
formData.append('title', action.questionObj.title);
formData.append('content', action.questionObj.content);
formData.append('tags', action.questionObj.tags);
console.info('formData: ', formData); // here the images field shows as undefined
try {
let options = {
method: 'POST',
headers: {
'Content-Type': 'multipart/form-data'
},
// body: JSON.stringify(action.questionObj),
body: formData,
};
const response = yield call(request, askQUrl, options);
if (response.data) {
yield put(submitQuestionSuccess(response.data));
} else {
yield put(submitQuestionFailed(response.error));
}
} catch(e) {
yield put(submitQuestionFailed('server problem in taking your question'));
}
}
}
当我提交带有title / content / tags和文件的表单时,我在浏览器控制台中收到以下错误:
在askQuestion中没有被捕获TypeError:无法读取属性'forEach' 未定义
我不确定为什么action.questionObj.images
未定义,因为在dropFile()
函数中,我将文件推送到images数组中。谁能发现我做错了什么?或者有更好的方法将文本和文件同时发布到基于sails.js的后端吗?