node.js - 如何仅在提交更改后而不是在更改期间提交更新的照片?
问题描述
我正在尝试让用户在登录时拥有默认个人资料图片的功能。然后他可以选择更新他的个人资料图片。
我得到了 95% 的工作我只是停留在最后一步。
这个过程是这样的:
1) 登录后,头像设置为默认头像。在 MYSQL 数据库中,我将 profilePic 字段设置为默认 profilePic
2)当用户改变他/她的图片时,它会改变profilePic的状态
3)当他们提交更改图片的请求时(onSubmit 函数),它将更新的图片上传到 AWS S3 并将 DB 字段更新为他/她选择的任何更新的文件名。
但是,这会带来一个问题,因为当图片更改时,它会破坏我在那里的默认图片(因为我更改了状态)并且在更改时 S3 中没有可用的图片,它只会在提交时更改。问题是,我需要将状态的文件名更改发送到服务器。
所以我的问题是,在他们提交并且图片在我的 S3 目录中可用并且进行了 db 更改之后,我如何才能将它放在哪里,在提交发生之前,该状态不会受到影响?
我想我可能需要使用生命周期方法,但我不是 100% 确定。
这是我的代码:
如果需要,我也会上传我的数据库查询和服务器代码。
看法:
import React from 'react';
import Header from '../common/Header';
import Base64 from 'base-64';
import { Modal, Button } from 'react-bootstrap';
import {Redirect} from 'react-router-dom';
import profileService from '../../services/Profilepage';
class Profilepage extends React.Component {
constructor(props){
super(props);
this.handleClose = this.handleClose.bind(this);
this.handleShow = this.handleShow.bind(this);
this.state = {
redirect: false,
firstName: '',
lastName: '',
email: '',
userName: '',
profilePic: '',
fileObject: '',
fileType: '',
fileSize: '',
filePayload: '',
errorMsg: false,
errorMsg2: false,
}
}
async userStatus(){
// Check if the user is logged in
if(localStorage.getItem('userData') === null) {
this.setState({redirect: true})
} else {
// Parse the data
const userObject = await JSON.parse(localStorage.getItem('userData'));
this.setState({
firstName: userObject.firstName,
lastName: userObject.lastName,
email: userObject.email,
userName: userObject.userName
})
}
}
handleClose(){
this.setState({
show:false,
// clear file state when modal closes
fileType: '',
fileSize: '',
fileObject: '',
filePayload: ''
});
}
handleShow(){
this.setState({
show:true
});
}
onChange(e){
var file = e.target.files[0];
var reader = new FileReader();
this.setState({
profilePic: file.name,
fileObject: e.target.files[0],
fileType: file.type,
fileSize: file.size,
});
reader.onload = (e) => {
this.setState({
filePayload: e.target.result
});
};
reader.readAsDataURL(file);
}
async onSubmit(e){
e.preventDefault();
console.log(this.state);
//Check if a uploaded photo was taken.
if(this.state.fileObject === ''){
this.setState({
errorMsg: true
})
}
else {
const updateData = {
userName: this.state.userName,
profilePic: this.state.profilePic,
fileType: this.state.fileType,
fileSize: this.state.fileSize,
filePayload: this.state.filePayload,
}
const updateprofileData = await profileService.updatePhoto(updateData)
//console.log(updateprofileData);
// Reload the page with users updated photo.
location.href='/Profilepage';
}
}
// Select users profilepic in database. Set it to state. However, this is what I'm stuck on cause if I change a picture with the onchange method, the picture will break because in S3, the picture isn't available until after the user has submitted the change.
async selectData(){
const selectData = {
profilePic: this.state.profilePic,
userName: this.state.userName
}
const selectprofileData = await profileService.selectPhoto(selectData)
this.setState({
profilePic: 'mys3linkishere' + this.state.profilePic
})
}
async componentDidMount(){
await this.userStatus();
await this.selectData();
}
render(){
if(this.state.redirect){
return(<Redirect to={'/'}/>)
}
return (
<div className="container">
<Header />
<div className="row">
<div className="col-md-5" id="profile-left">
<h1>Welcome, {this.state.userName}</h1>
<div className="img-rounded">
<img src={this.state.profilePic} alt="profile picture" />
</div>
<Button onClick={this.handleShow}>Upload New Photo</Button>
<Modal show={this.state.show} onHide={this.handleClose}>
<form
method="POST"
onSubmit={e => this.onSubmit(e)}
>
<Modal.Header closeButton>
<Modal.Title>Upload New Photo</Modal.Title>
</Modal.Header>
<Modal.Body>
{/* Please upload a photo. */}
{this.state.errorMsg === true ? <span style={{color: 'red'}}>Please upload a photo</span> : null}
<input
type="file"
className="form-control-file"
name="profilePic"
onChange={e => this.onChange(e)}
/>
</Modal.Body>
<Modal.Footer>
<Button type="submit" onClick={e => this.onSubmit(e)} bsStyle="primary">Upload Photo</Button>
</Modal.Footer>
</form>
</Modal>
</div>
</div>
</div>
)
}
}
export default Profilepage;
模型:
var db = require('../dbconnection');
var AWS = require('aws-sdk');
// AWS configuration
AWS.config.update({
accessKeyId: '....',
secretAccessKey: '....'
})
var profilePage = {
// Update users profilepic in database and insert photo in s3 bucket
updatePhoto: function(data, callback){
let uniqueprofilePic = data.userName + '-' + data.profilePic;
db.query('UPDATE users SET profilePic="'+uniqueprofilePic+'" WHERE userName="'+data.userName+'"')
//console.log(data);
var buf = new Buffer(data.filePayload.replace(/^data:image\/\w+;base64,/, ""),'base64');
var s3 = new AWS.S3();
var params = {
Bucket: 'mysimplebucket',
Key: uniqueprofilePic,
Body: buf,
ContentType: data.fileType,
ACL: 'public-read',
};
s3.putObject(params, function(err, data){
if(err) {
console.log(err, err.stack);
} else {
return data
console.log(data);
}
})
callback(true);
},
selectPhoto: function(data, callback){
db.query('SELECT * from users WHERE userName="'+data.userName+'"', callback)
}
}
module.exports = profilePage;
解决方案
好的,我理解这种情况的方式是,当调用 onChange 时,您将this.state.profilePic
状态设置为文件名。因此,当再次调用 render 方法时,该img
属性正在寻找文件的地址。相反,它只是获取文件名。
如果您想保持现状,那么我建议您更新 onChange 方法以包括将文件上传到 S3 的方法调用(setState
在 Onchange 之前),并确保网络往返在seState
. 然后,您可以在 onSubmit 期间更新您的数据库。我个人觉得解决方案有点讨厌,但它会完成任务。
或者
我意识到 Chrome 不允许您设置本地文件路径。this.state.profilePic
您可以在 onChange 期间将完整的本地文件路径设置为值。
像这样编辑 onChange 函数应该可以解决它-
reader.onload = (e) => {
this.setState({
filePayload: e.target.result,
profilePic: reader.result
});
};
并从之前的几行中删除 setState 。让我知道它是否有效!
推荐阅读
- matlab - 有什么方法可以为 App Designer 中的所有回调创建全局包装代码?
- javascript - 如何允许用户使用 CSRF TOken 通过 Swagger 登录?
- kubernetes - 你能从图表本身判断一个图表是使用 Helm 2 还是 3 吗?
- r - 如何在 R 中将 10 列收集到一个列中,将其他 10 列收集到另一个列中,仅使用 tidyverse 的计数和频率
- react-native - 在本机反应中给文本一些不透明的颜色
- javascript - 在 javascript 文件中定义对象时遇到问题
- node.js - v8 NAN 支持从 Nodejs 10 迁移到 14
- powershell - PowerShell - `begin` 块和外面的任何东西有什么区别?
- javascript - 属性或方法“消息”未在实例上定义,但在渲染期间引用
- php - 如何在 php 中将图像保存到服务器时硬编码数据库中的文件名?