node.js - 如何仅在提交更改后而不是更改期间提交更新的照片?

标签 node.js reactjs

我正在尝试提供一种功能,让用户在登录时拥有默认的个人资料图片。然后他可以选择更新其个人资料图片。

我已经完成了 95%,但我只是停留在最后一步。

这个过程是这样的:

1) 登录后,个人资料图片将设置为默认图片。在 MYSQL 数据库中,我有一个 profilePic 字段设置为默认的 profilePic

2)当用户更改他/她的图片时,它会更改 profilePic 的状态

3) 当他们提交更改图片的请求(onSubmit 函数)时,它会将更新的图片上传到 AWS S3,并将数据库字段更新为他/她选择的任何更新的文件名。

但是,这会带来一个问题,因为当图片更改时,它会破坏我在那里的默认图片(因为我更改了状态),并且更改时 S3 中没有可用图片,它仅在提交时更改。问题是,我需要将文件名更改状态发送到服务器。

所以我的问题是,在他们提交并且图片在我的 S3 目录中可用并且进行数据库更改后,如何才能将其保存到何处,在提交发生之前该状态不会受到影响?

我想我可能需要使用生命周期方法,但我不是 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 state 设置为文件名。因此,当再次调用 render 方法时,img 属性将查找文件的地址。相反,它只是获取文件名。

如果您想保持现状,那么我建议您更新 onChange 方法以包含将文件上传到 S3 的方法调用(在 Onchange 中 setState 之前),并确保网络往返在 seState 之前完成。然后您可以在 onSubmit 期间更新您的数据库。我个人觉得这个解决方案有点令人讨厌,但它会完成工作。

或者

您可以在 onChange 期间将完整的本地文件路径设置为 this.state.profilePic 的值。 我意识到 Chrome 不允许您设置本地文件路径。

像这样编辑 onChange 函数应该可以解决它 -

reader.onload = (e) => {
        this.setState({
            filePayload: e.target.result,
            profilePic: reader.result
        });
    };

并从之前的几行中删除 setState。 如果有效请告诉我!

关于node.js - 如何仅在提交更改后而不是更改期间提交更新的照片?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50106939/

相关文章:

javascript - 仅在一个组件中调用方法

html - 带边框半径的图像未填充 div

node.js - 文件更改时转译 ES6 并启动 Express 应用程序

javascript - 身份验证后 Yahoo API 出现问题

ios - React Native 数字键盘 returnKeyType 标签 iOS

javascript - 通过 TypeScript 导入和 Webpack2 使用 DatePicker

javascript - 是否可以异步定义 Mocha 测试?

node.js - 通过在 Docker 容器中缓存包来加速构建

javascript - V8 的大对象空间驻留在哪里?

reactjs - React - 将 refs 作为 prop 传递