Reactjs 如何在res.data之后设置两个不同的useState
我正在制作前端组件,将上传两个不同的图像,封面照片和用户的头像照片。我正在使用node.js作为我的express.js后端。如果用户上传封面照片,后端将发送res.send(如果图像是封面照片或阿凡达照片,它将保护图像路径)。但是我有一个问题,在用户上传图片之后,如何在中同时上传这两个图片。我曾经使用过不同的useState userInfo.coverPhoto和userInfo.avataphoto。问题是,用户单击封面照片后,再单击头像照片,封面照片的图像src将被破坏。但在刷新后,图像将出现在那里Reactjs 如何在res.data之后设置两个不同的useState,reactjs,Reactjs,我正在制作前端组件,将上传两个不同的图像,封面照片和用户的头像照片。我正在使用node.js作为我的express.js后端。如果用户上传封面照片,后端将发送res.send(如果图像是封面照片或阿凡达照片,它将保护图像路径)。但是我有一个问题,在用户上传图片之后,如何在中同时上传这两个图片。我曾经使用过不同的useState userInfo.coverPhoto和userInfo.avataphoto。问题是,用户单击封面照片后,再单击头像照片,封面照片的图像src将被破坏。但在刷新后,图像
userProfile.js
import React, { useState, useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import axios from 'axios';
import PersonIcon from '@material-ui/icons/Person';
import {
Container,
Grid,
Typography,
TextField,
Button,
Modal,
Backdrop,
} from '@material-ui/core';
import Card from '@material-ui/core/Card';
import CardContent from '@material-ui/core/CardContent';
import CardMedia from '@material-ui/core/CardMedia';
import ImageIcon from '@material-ui/icons/Image';
import AccountCircleIcon from '@material-ui/icons/AccountCircle';
import { useForm } from 'react-hook-form';
import FormContainer from '../components/FormContainer';
import useStyles from '../styles/style';
import {
getDetailsUser,
updateDetailsUser,
} from '../redux/actions/userActions';
const ProfilePage = ({ history }) => {
const userDetails = useSelector((state) => state.userDetails);
const { user } = userDetails;
const userLogin = useSelector((state) => state.userLogin);
const { userData } = userLogin;
const userUpdateDetails = useSelector((state) => state.userUpdateDetails);
const { userUpdate } = userUpdateDetails;
const [userInfo, setUserInfo] = useState({
id: user._id,
username: '',
email: '',
fullname: '',
coverPhoto: '',
avatarPhoto: '',
about: '',
mainAddress: '',
country: '',
city: '',
zipcode: '',
});
const [coverPreview, setCoverPreview] = useState('');
const [avatarPreview, setAvatarPreview] = useState('');
const [open, setOpen] = useState(false);
const dispatch = useDispatch();
const classes = useStyles();
useEffect(() => {
if (!userData) {
history.push('/user/login');
} else {
if (!user || !user.username || userUpdate) {
dispatch(getDetailsUser('profile'));
// if (!userInfo.coverPhoto) {
// document.getElementById(
// 'coverPhoto-file-button'
// ).nextElementSibling.style.opacity = '0';
// }
} else {
setUserInfo(user);
}
}
}, [userData, user, userUpdate, history]);
const handleClose = () => {
setOpen(false);
};
const handleChange = (level) => (e) => {
e.preventDefault();
if (!level) {
setUserInfo({
...userInfo,
[e.target.name]: e.target.value,
});
} else {
setUserInfo({
...userInfo,
[level]: {
...userInfo[level],
[e.target.name]: e.target.value,
},
});
}
};
const uploadCoverPhotoHandler = async (e) => {
const imgFile = e.target.files[0];
const imgFieldName = e.target.name;
if (imgFile.type !== 'image/jpeg' && imgFile.type !== 'image/png') {
console.log('wrong format');
}
let formData = new FormData();
formData.append(imgFieldName, imgFile);
try {
await axios({
method: 'POST',
url: 'http://localhost:5000/user/profile',
data: formData,
headers: {
'content-type': 'multipart/form-data',
},
}).then((res) => {
if (imgFieldName === 'coverPhoto') {
setUserInfo({ coverPhoto: res.data });
} else {
setUserInfo({ avatarPhoto: res.data });
}
});
} catch (error) {
console.log(error.response);
}
};
const onSubmit = async (e) => {
dispatch(updateDetailsUser(userInfo));
setOpen(true);
};
const { register, handleSubmit, errors, getValues } = useForm({
mode: 'onSubmit',
reValidateMode: 'onBlur',
});
return (
<FormContainer>
<Container component="div" className={classes.profileContainer}>
<Modal
className={classes.modal}
open={open}
closeAfterTransition
BackdropComponent={Backdrop}
BackdropProps={{
root: classes.modalRoot,
timeout: 500,
}}
>
<div className={classes.modalContainer}>
<Typography
component="h1"
variant="h5"
className={classes.promptTitle}
>
Account has been updated!
</Typography>
<Button
type="submit"
variant="contained"
className={classes.button}
onClick={handleClose}
style={{ width: '60%', marginBottom: '2.5rem' }}
>
Close
</Button>
</div>
</Modal>
<Grid item xs={12}>
<Card className={classes.userProfileCard}>
<CardContent>
<form noValidate onSubmit={handleSubmit(onSubmit)}>
<Typography
component="h1"
variant="h4"
className={classes.titleProfile}
>
<PersonIcon
style={{
position: 'relative',
top: '5px',
marginRight: '0.2em',
}}
/>
Edit Profile
</Typography>
<Grid container spacing={2}>
<Grid item xs={6}>
<TextField
variant="outlined"
id="username"
name="username"
type="text"
label="Username"
value={userInfo && userInfo.username}
onChange={handleChange()}
fullWidth
InputLabelProps={{
classes: {
root: classes.label,
focused: classes.focused,
},
shrink: true,
}}
InputProps={{
className: classes.textfield,
classes: {
root: classes.cssOutlinedInput,
focused: classes.cssFocused,
notchedOutline: classes.notchedOutline,
},
}}
inputRef={register({
required: 'You must provide an username.',
minLength: {
value: 4,
message:
'Your username must be greater than 4 characters',
},
pattern: {
value: /^[A-Za-z0-9_]+$/i,
message:
'Username may only have letters, number and underscores.',
},
})}
/>
{errors.username && (
<span className={classes.error}>
{errors.username.message}
</span>
)}
</Grid>
<Grid item xs={6}>
<TextField
variant="outlined"
id="email"
name="email"
type="email"
label="Email"
value={userInfo && userInfo.email}
onChange={handleChange()}
fullWidth
InputLabelProps={{
classes: {
root: classes.label,
focused: classes.focused,
},
shrink: true,
}}
InputProps={{
className: classes.textfield,
classes: {
root: classes.cssOutlinedInput,
focused: classes.cssFocused,
notchedOutline: classes.notchedOutline,
},
}}
inputRef={register({
required: 'You must provide a email.',
pattern: {
value: /^[^@ ]+@[^@ ]+\.[^@ .]{2,}$/,
message: 'You must provide a valid email address!',
},
})}
/>
{errors.email && (
<span className={classes.error}>
{errors.email.message}
</span>
)}
</Grid>
<Grid item xs={12}>
<TextField
variant="outlined"
id="fullname"
name="fullname"
type="text"
label="Fullname"
value={userInfo && userInfo.fullname}
onChange={handleChange()}
fullWidth
InputLabelProps={{
classes: {
root: classes.label,
focused: classes.focused,
},
shrink: true,
}}
InputProps={{
className: classes.textfield,
classes: {
root: classes.cssOutlinedInput,
focused: classes.cssFocused,
notchedOutline: classes.notchedOutline,
},
}}
inputRef={register({
required: 'You must provide a fullname.',
minLength: {
value: 6,
message:
'Your password must be greater than 6 characters',
},
pattern: {
value: /^[A-Za-z ]+$/i,
message: 'Alphabetical characters only',
},
})}
/>
{errors.fullname && (
<span className={classes.error}>
{errors.fullname.message}
</span>
)}
</Grid>
<Grid item xs={12}>
<TextField
variant="outlined"
id="mainAddress"
name="mainAddress"
type="text"
label="Address"
value={userInfo.address && userInfo.address.mainAddress}
onChange={handleChange('address')}
fullWidth
InputLabelProps={{
classes: {
root: classes.label,
focused: classes.focused,
},
shrink: true,
}}
InputProps={{
className: classes.textfield,
classes: {
root: classes.cssOutlinedInput,
focused: classes.cssFocused,
notchedOutline: classes.notchedOutline,
},
}}
/>
</Grid>
<Grid item xs={2}>
<TextField
variant="outlined"
id="city"
name="city"
type="text"
label="City"
value={userInfo.address && userInfo.address.city}
onChange={handleChange('address')}
fullWidth
InputLabelProps={{
classes: {
root: classes.label,
focused: classes.focused,
},
shrink: true,
}}
InputProps={{
className: classes.textfield,
classes: {
root: classes.cssOutlinedInput,
focused: classes.cssFocused,
notchedOutline: classes.notchedOutline,
},
}}
/>
</Grid>
<Grid item xs={2}>
<TextField
variant="outlined"
id="country"
name="country"
type="text"
label="Country"
value={userInfo.address && userInfo.address.country}
onChange={handleChange('address')}
fullWidth
InputLabelProps={{
classes: {
root: classes.label,
focused: classes.focused,
},
shrink: true,
}}
InputProps={{
className: classes.textfield,
classes: {
root: classes.cssOutlinedInput,
focused: classes.cssFocused,
notchedOutline: classes.notchedOutline,
},
}}
/>
</Grid>
<Grid item xs={2}>
<TextField
variant="outlined"
id="zipcode"
name="zipcode"
type="text"
label="Zipcode"
value={userInfo.address && userInfo.address.zipcode}
onChange={handleChange('address')}
fullWidth
InputLabelProps={{
shrink: true,
classes: {
root: classes.label,
focused: classes.focused,
},
}}
InputProps={{
className: classes.textfield,
classes: {
root: classes.cssOutlinedInput,
focused: classes.cssFocused,
notchedOutline: classes.notchedOutline,
},
}}
inputRef={register({
pattern: {
value: /^[0-9]+([0-9]+)?$/,
message: 'Numbers only',
},
})}
/>
{errors.zipcode && (
<span className={classes.error}>
{errors.zipcode.message}
</span>
)}
</Grid>
<Grid item xs={12}>
<Grid item xs={12}>
<TextField
variant="outlined"
id="aboutme"
name="about"
type="text"
label="About me"
value={userInfo && userInfo.about}
onChange={handleChange()}
fullWidth
multiline
rows={2}
InputLabelProps={{
classes: {
root: classes.label,
focused: classes.focused,
},
shrink: true,
}}
InputProps={{
className: classes.textfield,
classes: {
root: classes.cssOutlinedInput,
focused: classes.cssFocused,
notchedOutline: classes.notchedOutline,
},
}}
/>
</Grid>
</Grid>
<Grid item xs={2}>
<Button
type="submit"
fullWidth
variant="contained"
className={classes.button}
>
Update
</Button>
</Grid>
</Grid>
</form>
</CardContent>
</Card>
</Grid>
<Grid item xs={12}>
<Card className={classes.userCard}>
<form id="userPhoto">
<CardContent className={classes.coverPhotoContainer}>
<CardMedia
component="img"
src={userInfo && userInfo.coverPhoto}
height="180rem"
onload="this.style.display=''"
/>
<input
accept="image/*"
id="coverPhoto-file-button"
type="file"
name="coverPhoto"
style={{ display: 'none' }}
onChange={uploadCoverPhotoHandler}
/>
<label htmlFor="coverPhoto-file-button">
<ImageIcon />
Add Cover Photo
</label>
</CardContent>
<CardContent className={classes.imgProfileContainer}>
<CardMedia
component="img"
src={userInfo && userInfo.avatarPhoto}
height="180rem"
onload="this.style.display=''"
/>
<input
accept="image/*"
id="imgProfile-file-button"
type="file"
name="avatarPhoto"
style={{ display: 'none' }}
onChange={uploadCoverPhotoHandler}
/>
<label htmlFor="imgProfile-file-button">
<AccountCircleIcon />
</label>
</CardContent>
</form>
<CardContent>
<Typography
className={classes.titleProfileUsername}
variant="h6"
component="h1"
>
{userInfo && userInfo.username}
</Typography>
<Typography
className={classes.profileAbout}
variant="body2"
component="p"
></Typography>
</CardContent>
</Card>
</Grid>
</Container>
</FormContainer>
);
};
export default ProfilePage;
userProfile.js
从“React”导入React,{useState,useffect};
从'react redux'导入{useDispatch,useSelector};
从“axios”导入axios;
从“@material ui/icons/Person”导入PersonIcon;
进口{
集装箱,
网格,
排版,
TextField,
按钮
情态动词
背景
}来自“@material ui/core”;
从“@material ui/core/Card”导入卡片;
从“@material ui/core/CardContent”导入CardContent;
从“@material ui/core/CardMedia”导入CardMedia;
从“@material ui/icons/Image”导入ImageIcon;
从“@material ui/icons/AccountCircle”导入AccountCircleIcon;
从“react hook form”导入{useForm};
从“../components/FormContainer”导入FormContainer;
从“../styles/style”导入useStyles;
进口{
getDetailsUser,
更新的tailsuser,
}来自“../redux/actions/userActions”;
const ProfilePage=({history})=>{
const userDetails=useSelector((state)=>state.userDetails);
const{user}=userDetails;
const userLogin=useSelector((state)=>state.userLogin);
const{userData}=userLogin;
const userUpdateDetails=useSelector((state)=>state.userUpdateDetails);
const{userUpdate}=userUpdateDetails;
const[userInfo,setUserInfo]=useState({
id:user.\u id,
用户名:“”,
电子邮件:“”,
全名:“”,
封面照片:'',
阿凡达照片:'',
关于:'',
主地址:'',
国家:“,
城市:'',
zipcode:“”,
});
const[coverPreview,setCoverPreview]=useState(“”);
const[avatarPreview,setAvatarPreview]=使用状态(“”);
const[open,setOpen]=useState(false);
const dispatch=usedpatch();
const classes=useStyles();
useffect(()=>{
如果(!userData){
history.push('/user/login');
}否则{
如果(!user | |!user.username | | userUpdate){
调度(getDetailsUser(“配置文件”);
//如果(!userInfo.coverPhoto){
//document.getElementById(
//“封面照片文件按钮”
//).nextElementSibling.style.opacity='0';
// }
}否则{
setUserInfo(用户);
}
}
},[userData,user,userUpdate,history]);
常量handleClose=()=>{
setOpen(假);
};
常量句柄更改=(级别)=>(e)=>{
e、 预防默认值();
如果(!级别){
setUserInfo({
…用户信息,
[e.target.name]:e.target.value,
});
}否则{
setUserInfo({
…用户信息,
[级别]:{
…用户信息[级别],
[e.target.name]:e.target.value,
},
});
}
};
const uploadCoverPhotoHandler=异步(e)=>{
const imgFile=e.target.files[0];
常量imgFieldName=e.target.name;
if(imgFile.type!=“image/jpeg”&&imgFile.type!=“image/png”){
console.log(“格式错误”);
}
设formData=new formData();
formData.append(imgFieldName,imgFile);
试一试{
等待axios({
方法:“POST”,
网址:'http://localhost:5000/user/profile',
数据:formData,
标题:{
“内容类型”:“多部分/表单数据”,
},
})。然后((res)=>{
如果(imgFieldName===‘封面照片’){
setUserInfo({coverPhoto:res.data});
}否则{
setUserInfo({avataphoto:res.data});
}
});
}捕获(错误){
console.log(error.response);
}
};
const onSubmit=async(e)=>{
调度(更新的用户信息);
setOpen(真);
};
常量{register,handleSubmit,errors,getValues}=useForm({
模式:“onSubmit”,
重新验证模式:“onBlur”,
});
返回(
帐户已更新!
接近
编辑配置文件
{errors.username&&(
{错误.用户名.消息}
)}
{errors.email&&(
{errors.email.message}
)}
{errors.fullname&&(
{errors.fullname.message}
)}
{errors.zipcode&&(
{errors.zipcode.message}
)}
更新
}).then((res) => {
if (imgFieldName === 'coverPhoto') {
setUserInfo(prevState => ({ ...prevState, coverPhoto: res.data }));
} else {
setUserInfo(prevState => ({ ...prevState, avatarPhoto: res.data }));
}
});